/******************************************************************************
 *
 *  Copyright (C) 2019-2021 Aicsemi Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  Filename:      userial_vendor.c
 *
 *  Description:   Contains vendor-specific userial functions
 *
 ******************************************************************************/
#undef NDEBUG
#define LOG_TAG "bt_userial_vendor"

#include <utils/Log.h>
#include <termios.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <sys/eventfd.h>
#include "userial.h"
#include "userial_vendor.h"
#include "aic_socket.h"
#include <cutils/sockets.h>
#include "upio.h"
#include "hardware.h"

#ifdef CONFIG_SCO_OVER_HCI
#include "sbc.h"
#ifdef CONFIG_SCO_MSBC_PLC
#include "sbcplc.h"
unsigned char indices0[] = {0xad, 0x0, 0x0, 0xc5, 0x0, 0x0, 0x0, 0x0, 0x77, 0x6d,
                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00}; //padding at the end
#endif
#include <sys/ioctl.h>
#include <stdlib.h>
#include <fcntl.h>
#include "lowcfe_v3.h"

#define SET_SCO_OPEN	_IOR('E', 181, int)
#define SET_SCO_CLOSE	_IOR('E', 182, int)
#define SET_UART_SCO_OPEN    0x50
#define SET_UART_SCO_CLOSE   0x51
#define SET_SELECT_MSBC      0x52

enum {
  BTIF_AIC_SCO_STATE_OFF,
  BTIF_AIC_SCO_STATE_ON
};

typedef struct {
  pthread_t  worker_thread;
  bool worker_thread_running;
  pthread_mutex_t worker_recv_mutex;
  pthread_cond_t worker_thread_cond;
  RTB_QUEUE_HEAD* data_msg_queue;
  RTB_QUEUE_HEAD* snd_recv_msg_queue;
  int fd_t;
  uint8_t snd_sco_count;
  uint8_t air_mode;
} tBTIF_AIC_SCO_CB;

static tBTIF_AIC_SCO_CB btif_aic_sco_cb;
static int btif_aic_sco_state = BTIF_AIC_SCO_STATE_OFF;
static char fname[255] = "/dev/aic_uart_sco_dev";
LowcFE_c lc;
#if AIC_PLC_EN
bool aic_plc_en=false;
#endif

#endif
/******************************************************************************
**  Constants & Macros
******************************************************************************/

#ifndef VNDUSERIAL_DBG
#define VNDUSERIAL_DBG TRUE
#endif

#if (VNDUSERIAL_DBG == TRUE)
#define VNDUSERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
#else
#define VNDUSERIALDBG(param, ...) {}
#endif

#define VND_PORT_NAME_MAXLEN    256

#ifndef BT_CHIP_HW_FLOW_CTRL_ON
#define BT_CHIP_HW_FLOW_CTRL_ON TRUE
#endif

/******************************************************************************
**  Extern functions
******************************************************************************/
extern char aicbt_transtype;
extern void Heartbeat_cleanup();
extern void Heartbeat_init();
extern int AIC_btservice_init();

/******************************************************************************
**  Local type definitions
******************************************************************************/
#if !defined(EFD_SEMAPHORE)
#  define EFD_SEMAPHORE (1 << 0)
#endif

#define AIC_DATA_RECEIVED 1
#define AIC_DATA_SEND     0
struct aic_object_t {
  int fd;                              // the file descriptor to monitor for events.
  void *context;                       // a context that's passed back to the *_ready functions..
  pthread_mutex_t lock;                // protects the lifetime of this object and all variables.

  void (*read_ready)(void *context);   // function to call when the file descriptor becomes readable.
  void (*write_ready)(void *context);  // function to call when the file descriptor becomes writeable.
};

/* vendor serial control block */
typedef struct {
    int fd;                     /* fd to Bluetooth device */
    int uart_fd[2];
    int signal_fd[2];
    int epoll_fd;
    int cpoll_fd;
    int event_fd;
    struct termios termios;     /* serial terminal of BT port */
    char port_name[VND_PORT_NAME_MAXLEN];
    pthread_t thread_socket_id;
    pthread_t thread_uart_id;
    pthread_t thread_coex_id;
    bool thread_running;

    RTB_QUEUE_HEAD *recv_data;
    RTB_QUEUE_HEAD *send_data;
    RTB_QUEUE_HEAD *data_order;
    volatile bool  btdriver_state;
    volatile bool  is_hardware_err;
} vnd_userial_cb_t;

#ifdef CONFIG_SCO_OVER_HCI

enum esco_coding_format {
    ESCO_CODING_FORMAT_ULAW     = 0x00,
    ESCO_CODING_FORMAT_ALAW     = 0x01,
    ESCO_CODING_FORMAT_CVSD     = 0x02,
    ESCO_CODING_FORMAT_TRANSPNT = 0x03,
    ESCO_CODING_FORMAT_LINEAR   = 0x04, // PCM raw data
    ESCO_CODING_FORMAT_MSBC     = 0x05,
    ESCO_CODING_FORMAT_VS       = 0xFF,
};

enum esco_data_path {
    ESCO_DATA_PATH_HCI  = 0x00,
    ESCO_DATA_PATH_PCM  = 0x01,
    ESCO_DATA_PATH_TEST = 0xFF,
};

struct coding_format_t {
    uint8_t coding_format;
    uint8_t reserved[4];
} __attribute__ ((packed));

struct esco_para_t {
    uint32_t transmit_bandwidth;
    uint32_t receive_bandwidth;
    struct   coding_format_t transmit_coding_format;
    struct   coding_format_t receive_coding_format;
    uint16_t transmit_codec_frame_size;
    uint16_t receive_codec_frame_size;
    uint32_t input_bandwidth;
    uint32_t output_bandwidth;
    struct   coding_format_t input_coding_format;
    struct   coding_format_t output_coding_format;
    uint16_t input_coded_data_size;
    uint16_t output_coded_data_size;
    uint8_t  input_pcm_data_format;
    uint8_t  output_pcm_data_format;
    uint8_t  input_pcm_sample_payload_msb_pos;
    uint8_t  output_pcm_sample_payload_msb_pos;
    uint8_t  input_data_path;
    uint8_t  output_data_path;
    uint8_t  input_transport_unit_size;
    uint8_t  output_transport_unit_size;
    uint16_t max_latency;
    uint16_t packet_types;
    uint8_t  retransmission_effort;
} __attribute__ ((packed));

struct codec_para_t {
    uint8_t  input_format;
    uint8_t  input_channels;
    uint8_t  input_bits;
    uint16_t input_rate;
    uint8_t  output_format;
    uint8_t  output_channels;
    uint8_t  output_bits;
    uint16_t output_rate;
} __attribute__ ((packed));

uint16_t btui_msbc_h2[] = {0x0801,0x3801,0xc801,0xf801};
typedef struct {
    pthread_mutex_t sco_recv_mutex;
    pthread_cond_t  sco_recv_cond;
    pthread_mutex_t msbc_recv_mutex;
    pthread_mutex_t msbc_send_mutex;
    pthread_cond_t msbc_send_cond;
    pthread_t thread_socket_sco_id;
    pthread_t thread_recv_sco_id;
    pthread_t thread_send_sco_id;
    uint16_t  sco_handle;
    bool thread_sco_running;
    bool thread_recv_sco_running;
    bool thread_send_sco_running;
    uint16_t voice_settings;
    RTB_QUEUE_HEAD *recv_sco_data;
    RTB_QUEUE_HEAD *send_sco_data;
    RTB_QUEUE_HEAD *recv_msbc_dec_data;
    RTB_QUEUE_HEAD *send_msbc_enc_data;
    unsigned char enc_data[480];
    unsigned int current_pos;
    uint16_t sco_packet_len;
    struct esco_para_t esco_para;
    struct codec_para_t codec_para;
    sbc_t sbc_dec, sbc_enc;
    uint32_t pcm_enc_seq;
    int8_t pcm_dec_seq;
    uint32_t pcm_dec_frame;
    int signal_fd[2];
} sco_cb_t;
#endif

/******************************************************************************
**  Static functions
******************************************************************************/
static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length);
static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, uint16_t length) ;
extern void AIC_btservice_destroyed();
static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length);
static void userial_recv_uart_rawdata(unsigned char *buffer, unsigned int total_length);
static int close_state = -1;
/******************************************************************************
**  Static variables
******************************************************************************/
#ifdef CONFIG_SCO_OVER_HCI
static sco_cb_t sco_cb = {
    .codec_para = {
        .input_channels = 1,
        .input_bits = 16,
        .input_rate = 8000,
        .output_channels = 1,
        .output_bits = 16,
        .output_rate = 8000,
    },
};
#endif
static vnd_userial_cb_t vnd_userial;
static const hci_h5_t *h5_int_interface;
static int packet_recv_state = AICBT_PACKET_IDLE;
static unsigned int packet_bytes_need = 0;
static serial_data_type_t current_type = 0;
static struct aic_object_t aic_socket_object;

static unsigned char h4_read_buffer[2048] = {0};
static int h4_read_length = 0;

static int coex_packet_recv_state = AICBT_PACKET_IDLE;
static int coex_packet_bytes_need = 0;
static serial_data_type_t coex_current_type = 0;
static unsigned char coex_resvered_buffer[2048] = {0};
static int coex_resvered_length = 0;

#ifdef AIC_HANDLE_EVENT
static int received_packet_state = AICBT_PACKET_IDLE;
static unsigned int received_packet_bytes_need = 0;
static serial_data_type_t recv_packet_current_type = 0;
static unsigned char received_resvered_header[2048] = {0};
static int received_resvered_length = 0;
static aicbt_version_t aicbt_version;
static aicbt_lescn_t  aicbt_adv_con;
#endif

static hci_h5_callbacks_t h5_int_callbacks = {
    .h5_int_transmit_data_cb = h5_int_transmit_data_cb,
    .h5_data_ready_cb = h5_data_ready_cb,
};

static const uint8_t hci_preamble_sizes[] = {
    COMMAND_PREAMBLE_SIZE,
    ACL_PREAMBLE_SIZE,
    SCO_PREAMBLE_SIZE,
    EVENT_PREAMBLE_SIZE
};

bool aic_ble_only = false;
static uint8_t chgloclname[252];
static uint8_t eir[245];
static uint8_t cod[7];
static uint8_t simple_pair_mode[5];
static uint8_t le_host_support[6];
static uint8_t secure_conn_host_support[5];
static uint8_t le_set_event_mask[12];
static uint8_t set_event_mask[12];
static uint8_t set_le_random_addr[10];
static uint8_t white_list_list[10][11];
static bool aic_check_store_white_list(uint8_t* addr)
{
    bool ret = false;
    int i = 0;
    for(i = 0 ;i < 10; i++){
		if(white_list_list[i][0] != 0){
	        if(white_list_list[i][5] == addr[0] 
			&& white_list_list[i][6] == addr[1]
			&& white_list_list[i][7] == addr[2]
			&& white_list_list[i][8] == addr[3]
			&& white_list_list[i][9] == addr[4]
			&& white_list_list[i][10] == addr[5]){
	            ret = true;
	            break;
	        }
		}
    }
    ALOGE("%s,addr = %x %x %x %x %x %x,ret = %d\n", __func__,addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],ret);
    return ret;
}

static bool aic_store_white_list(unsigned char *recv_buffer, int total_length)
{
    bool ret = false;
    int i = 0;
    for(i = 0 ;i < 10; i++){
        if(white_list_list[i][0] == 0){
            ret = true;
			memcpy(&white_list_list[i][1],recv_buffer,total_length);
			white_list_list[i][0] = 1;
            break;
        }
    }
    ALOGE("%s,addr = %x %x %x %x %x %x,ret = %d\n", __func__,recv_buffer[5],recv_buffer[6],recv_buffer[7],recv_buffer[8],recv_buffer[9],recv_buffer[10],ret);
    return ret;
}
static void aic_clean_store_white_list(uint8_t* addr)
{
    int i = 0;
    ALOGE("%s,addr = %x %x %x %x %x %x\n", __func__,addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]);
    for(i = 0 ;i < 10; i++){
        if(white_list_list[i][0] == 1 
		&& (white_list_list[i][5] == addr[0] 
			&& white_list_list[i][6] == addr[1]
			&& white_list_list[i][7] == addr[2]
			&& white_list_list[i][8] == addr[3]
			&& white_list_list[i][9] == addr[4]
			&& white_list_list[i][10] == addr[5])){
            memset(white_list_list[i],0,11);
			ALOGE("clean success\n");
            break;
        }
    }
}

static void aic_clean_all_store_white_list(void)
{
    int i = 0;
    for(i = 0 ;i < 10; i++){
		memset(white_list_list[i],0,11);
    }
    ALOGE("%s\n", __func__);
}

static int aic_resume_all_store_white_list(void)
{
    int i = 0;
    int ret = 0;
    ALOGE("%s\n", __func__);
    for(i = 0 ;i < 10; i++){
        if(white_list_list[i][0] == 1){
			ALOGE("%s,addr = %x %x %x %x %x %x\n", __func__,white_list_list[i][5],white_list_list[i][6],white_list_list[i][7],white_list_list[i][8],white_list_list[i][9],white_list_list[i][10]);
			h4_int_transmit_data(white_list_list[i], 11);
            ms_delay(2);
            ret = 1;
        }
    }
    ALOGE("%s ret = %d\n", __func__,ret);
    return ret;
}

#if 1
uint16_t aic_acl_handle_list[10];
void hci_disconnect_complete_event(uint16_t handle,uint8_t reason)
{
    int len = 7;
    unsigned char p_buf[7] = {HCIT_TYPE_EVENT, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00};
    p_buf[4] = (unsigned char)(handle & 0x00ff);
    p_buf[5] = (unsigned char)((handle & 0xff00)>>8);
    p_buf[6] = reason;
    ALOGE("%s\n",__func__);
    userial_recv_rawdata_hook(p_buf,len);
}

static bool aic_check_store_handle(uint16_t handle)
{
    bool ret = false;
    int i = 0;
    for(i = 0 ;i < 10; i++){
        if(aic_acl_handle_list[i] == handle && aic_acl_handle_list[i] != 0){
            ret = true;
            break;
        }
    }
    ALOGE("%s,handle = 0x%x,ret = %d\n", __func__,handle,ret);
    return ret;
}

static bool aic_store_acl_handle(uint16_t handle)
{
    bool ret = false;
    int i = 0;
    for(i = 0 ;i < 10; i++){
        if(aic_acl_handle_list[i] != handle && aic_acl_handle_list[i] == 0){
            aic_acl_handle_list[i] = handle;
            ret = true;
            break;
        }
    }
    ALOGE("%s,handle = 0x%x,ret = %d\n", __func__,handle,ret);
    return ret;
}
static void aic_clean_store_acl_handle(uint16_t handle)
{
    int i = 0;
    ALOGE("%s,handle = 0x%x\n", __func__,handle);
    for(i = 0 ;i < 10; i++){
        if(aic_acl_handle_list[i] == handle && aic_acl_handle_list[i] != 0){
            aic_acl_handle_list[i] = 0;
            break;
        }
    }
}

static void aic_clean_all_store_acl_handle(void)
{
    int i = 0;
    for(i = 0 ;i < 10; i++){
        aic_acl_handle_list[i] = 0;
    }
    ALOGE("%s\n", __func__);
}

static int aic_disconnect_all_store_acl_handle()
{
    int i = 0;
    int ret = 0;
    ALOGE("%s\n", __func__);
    for(i = 0 ;i < 10; i++){
        if(aic_acl_handle_list[i] != 0){
            ALOGE("%s,handle = 0x%x\n", __func__,aic_acl_handle_list[i]);
			if(aic_acl_handle_list[i]>=0x10){
            	hci_disconnect_complete_event(aic_acl_handle_list[i],0x13);
			}
            aic_clean_store_acl_handle(aic_acl_handle_list[i]);
            ret = 1;
        }
    }
    ALOGE("%s ret = %d\n", __func__,ret);
    return ret;
}


#endif

/*****************************************************************************
**   Helper Functions
*****************************************************************************/

/*******************************************************************************
**
** Function        userial_to_tcio_baud
**
** Description     helper function converts USERIAL baud rates into TCIO
**                  conforming baud rates
**
** Returns         TRUE/FALSE
**
*******************************************************************************/
uint8_t userial_to_tcio_baud(uint8_t cfg_baud, uint32_t *baud)
{

    AICBTDBG(LOGINFO, "%s cfg_baud:%d", __func__, cfg_baud);

    if (cfg_baud == USERIAL_BAUD_115200)
        *baud = B115200;
    else if (cfg_baud == USERIAL_BAUD_4M)
        *baud = B4000000;
    else if (cfg_baud == USERIAL_BAUD_3_5M)
        *baud = B3500000;
    else if (cfg_baud == USERIAL_BAUD_3M)
        *baud = B3000000;
    else if (cfg_baud == USERIAL_BAUD_2_5M)
        *baud = B2500000;
    else if (cfg_baud == USERIAL_BAUD_2M)
        *baud = B2000000;
    else if (cfg_baud == USERIAL_BAUD_1_5M)
        *baud = B1500000;
    else if (cfg_baud == USERIAL_BAUD_1M)
        *baud = B1000000;
    else if (cfg_baud == USERIAL_BAUD_921600)
        *baud = B921600;
    else if (cfg_baud == USERIAL_BAUD_460800)
        *baud = B460800;
    else if (cfg_baud == USERIAL_BAUD_230400)
        *baud = B230400;
    else if (cfg_baud == USERIAL_BAUD_57600)
        *baud = B57600;
    else if (cfg_baud == USERIAL_BAUD_19200)
        *baud = B19200;
    else if (cfg_baud == USERIAL_BAUD_9600)
        *baud = B9600;
    else if (cfg_baud == USERIAL_BAUD_1200)
        *baud = B1200;
    else if (cfg_baud == USERIAL_BAUD_600)
        *baud = B600;
    else {
        AICBTDBG(LOGERROR, "userial vendor open: unsupported baud idx %i", cfg_baud);
        *baud = B115200;
        return FALSE;
    }

    return TRUE;
}

#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
/*******************************************************************************
**
** Function        userial_ioctl_init_bt_wake
**
** Description     helper function to set the open state of the bt_wake if ioctl
**                  is used. it should not hurt in the rfkill case but it might
**                  be better to compile it out.
**
** Returns         none
**
*******************************************************************************/
void userial_ioctl_init_bt_wake(int fd)
{
    uint32_t bt_wake_state;

    /* assert BT_WAKE through ioctl */
    ioctl(fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
    ioctl(fd, USERIAL_IOCTL_BT_WAKE_GET_ST, &bt_wake_state);
    VNDUSERIALDBG("userial_ioctl_init_bt_wake read back BT_WAKE state=%i", \
               bt_wake_state);
}
#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)


/*****************************************************************************
**   Userial Vendor API Functions
*****************************************************************************/
static void userial_send_hw_error()
{
    unsigned char p_buf[100];
    int length;
    ALOGE("%s, is_true = %d\n",__func__,vnd_userial.is_hardware_err);
    if(vnd_userial.is_hardware_err == true){
        return;
    }
    if(aic_disconnect_all_store_acl_handle() )
        ms_delay(1);
    #if 0
    p_buf[0] = HCIT_TYPE_EVENT;//event
    p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
    p_buf[3] = 0x01;// host log opcode
    length = sprintf((char *)&p_buf[4], "host stack: userial error \n");
    p_buf[2] = length + 2;//len
    length = length + 1 + 4;
    userial_recv_rawdata_hook(p_buf,length);
    #endif
    length = 4;
    p_buf[0] = HCIT_TYPE_EVENT;//event
    p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
    p_buf[2] = 0x01;//len
    p_buf[3] = USERIAL_HWERR_CODE_AIC;//userial error code
    userial_recv_rawdata_hook(p_buf,length);
}


/*******************************************************************************
**
** Function        userial_vendor_init
**
** Description     Initialize userial vendor-specific control block
**
** Returns         None
**
*******************************************************************************/
void userial_vendor_init(char *bt_device_node)
{
    aic_clean_all_store_acl_handle();
	aic_clean_all_store_white_list();
#ifdef AIC_HANDLE_EVENT
    memset(&aicbt_adv_con, 0, sizeof(aicbt_lescn_t));
#endif
    memset(&vnd_userial, 0, sizeof(vnd_userial_cb_t));
    vnd_userial.fd = -1;
    vnd_userial.is_hardware_err = false;
    char value[100];
    snprintf(vnd_userial.port_name, VND_PORT_NAME_MAXLEN, "%s", \
            bt_device_node);
#if 0
    if (aicbt_transtype & AICBT_TRANS_H5) {
        h5_int_interface = hci_get_h5_int_interface();
        h5_int_interface->h5_int_init(&h5_int_callbacks);
    }
#endif

    vnd_userial.data_order = RtbQueueInit();
    vnd_userial.recv_data = RtbQueueInit();
    vnd_userial.send_data = RtbQueueInit();

    //reset coex gloable variables
    coex_packet_recv_state = AICBT_PACKET_IDLE;
    coex_packet_bytes_need = 0;
    coex_current_type = 0;
    coex_resvered_length = 0;

#ifdef AIC_HANDLE_EVENT
    //reset handle event gloable variables
    received_packet_state = AICBT_PACKET_IDLE;
    received_packet_bytes_need = 0;
    recv_packet_current_type = 0;
    received_resvered_length = 0;
#endif

#ifdef CONFIG_SCO_OVER_HCI
    sco_cb.recv_sco_data = RtbQueueInit();
    sco_cb.send_sco_data = RtbQueueInit();
    sco_cb.recv_msbc_dec_data = RtbQueueInit();
    sco_cb.send_msbc_enc_data = RtbQueueInit();
    pthread_mutex_init(&sco_cb.sco_recv_mutex, NULL);
    pthread_cond_init(&sco_cb.sco_recv_cond, NULL);
    pthread_mutex_init(&sco_cb.msbc_recv_mutex, NULL);
    pthread_mutex_init(&sco_cb.msbc_send_mutex, NULL);
    pthread_cond_init(&sco_cb.msbc_send_cond, NULL);
    #if 0
    memset(&sco_cb.sbc_enc, 0, sizeof(sbc_t));
    sbc_init_msbc(&sco_cb.sbc_enc, 0L);
    sco_cb.sbc_enc.endian = SBC_LE;
    memset(&sco_cb.sbc_dec, 0, sizeof(sbc_t));
    sbc_init_msbc(&sco_cb.sbc_dec, 0L);
    sco_cb.sbc_dec.endian = SBC_LE;
    #endif
#if AIC_SCO_UART_SUPPORT
    memset(&btif_aic_sco_cb, 0, sizeof(btif_aic_sco_cb));
    ALOGE("%s open aic_sco_uart fname:%s ", __func__, fname);
    btif_aic_sco_cb.fd_t = open(fname, O_RDWR| O_SYNC);
    if (btif_aic_sco_cb.fd_t < 0) {
        ALOGE("%s fd error %s", __func__,strerror(errno));
    }else{
        ALOGE("%s fd = %d", __func__,btif_aic_sco_cb.fd_t );
    }
    btif_aic_sco_cb.data_msg_queue = RtbQueueInit();
    btif_aic_sco_cb.snd_recv_msg_queue = RtbQueueInit();
    pthread_cond_init(&btif_aic_sco_cb.worker_thread_cond, NULL);
    pthread_mutex_init(&btif_aic_sco_cb.worker_recv_mutex, NULL);
#endif

#endif
}


/*******************************************************************************
**
** Function        userial_vendor_open
**
** Description     Open the serial port with the given configuration
**
** Returns         device fd
**
*******************************************************************************/
int userial_vendor_open(tUSERIAL_CFG *p_cfg)
{
    uint32_t baud;
    uint8_t data_bits;
    uint16_t parity;
    uint8_t stop_bits;

    vnd_userial.fd = -1;

    if (!userial_to_tcio_baud(p_cfg->baud, &baud)) {
        return -1;
    }

    if (p_cfg->fmt & USERIAL_DATABITS_8)
        data_bits = CS8;
    else if (p_cfg->fmt & USERIAL_DATABITS_7)
        data_bits = CS7;
    else if (p_cfg->fmt & USERIAL_DATABITS_6)
        data_bits = CS6;
    else if (p_cfg->fmt & USERIAL_DATABITS_5)
        data_bits = CS5;
    else {
        AICBTDBG(LOGERROR, "userial vendor open: unsupported data bits");
        return -1;
    }

    if (p_cfg->fmt & USERIAL_PARITY_NONE)
        parity = 0;
    else if (p_cfg->fmt & USERIAL_PARITY_EVEN)
        parity = PARENB;
    else if (p_cfg->fmt & USERIAL_PARITY_ODD)
        parity = (PARENB | PARODD);
    else {
        AICBTDBG(LOGERROR,"userial vendor open: unsupported parity bit mode");
        return -1;
    }

    if (p_cfg->fmt & USERIAL_STOPBITS_1)
        stop_bits = 0;
    else if (p_cfg->fmt & USERIAL_STOPBITS_2)
        stop_bits = CSTOPB;
    else {
        AICBTDBG(LOGERROR,"userial vendor open: unsupported stop bits");
        return -1;
    }

    AICBTDBG(LOGINFO, "userial vendor open: opening %s", vnd_userial.port_name);

    if ((vnd_userial.fd = open(vnd_userial.port_name, O_RDWR)) == -1) {
        AICBTDBG(LOGERROR, "userial vendor open: unable to open %s", vnd_userial.port_name);
        return -1;
    }

    tcflush(vnd_userial.fd, TCIOFLUSH);

    tcgetattr(vnd_userial.fd, &vnd_userial.termios);
    cfmakeraw(&vnd_userial.termios);
    vnd_userial.termios.c_cflag |= (CRTSCTS | stop_bits);
    
    tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios);
    tcflush(vnd_userial.fd, TCIOFLUSH);

    tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios);
    tcflush(vnd_userial.fd, TCIOFLUSH);
    tcflush(vnd_userial.fd, TCIOFLUSH);

    /* set input/output baudrate */
    AICBTDBG(LOGINFO, "userial vendor set baudrate %d", baud);
    cfsetospeed(&vnd_userial.termios, baud);
    cfsetispeed(&vnd_userial.termios, baud);
    tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios);

#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
    userial_ioctl_init_bt_wake(vnd_userial.fd);
#endif

    vnd_userial.btdriver_state = true;
    AICBTDBG(LOGINFO, "device fd = %d open", vnd_userial.fd);

    return vnd_userial.fd;
}

static void userial_socket_close(void)
{
    int result;

    if ((vnd_userial.uart_fd[0] > 0) && (result = close(vnd_userial.uart_fd[0])) < 0)
        AICBTDBG(LOGERROR, "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[0], result);

    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.uart_fd[1], NULL) == -1)
        AICBTDBG(LOGERROR, "%s unable to unregister fd %d from epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));

    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.signal_fd[1], NULL) == -1)
        AICBTDBG(LOGERROR, "%s unable to unregister signal fd %d from epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));

    if ((vnd_userial.uart_fd[1] > 0) && (result = close(vnd_userial.uart_fd[1])) < 0)
        AICBTDBG(LOGERROR, "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[1], result);

    if (vnd_userial.thread_socket_id != -1){
        if ((result = pthread_join(vnd_userial.thread_socket_id, NULL)) < 0)
            AICBTDBG(LOGERROR, "%s vnd_userial.thread_socket_id pthread_join_failed", __func__);
        else {
            vnd_userial.thread_socket_id = -1;
            AICBTDBG(LOGINFO, "%s vnd_userial.thread_socket_id pthread_join_success", __func__);
        }
    }
    if (vnd_userial.epoll_fd > 0)
        close(vnd_userial.epoll_fd);

    if ((vnd_userial.signal_fd[0] > 0) && (result = close(vnd_userial.signal_fd[0])) < 0)
        AICBTDBG(LOGERROR, "%s (signal fd[0]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[0], result);
    if ((vnd_userial.signal_fd[1] > 0) && (result = close(vnd_userial.signal_fd[1])) < 0)
        AICBTDBG(LOGERROR, "%s (signal fd[1]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[1], result);

    vnd_userial.epoll_fd = -1;
    vnd_userial.uart_fd[0] = -1;
    vnd_userial.uart_fd[1] = -1;
    vnd_userial.signal_fd[0] = -1;
    vnd_userial.signal_fd[1] = -1;
}

static void userial_uart_close(void)
{
    int result;
    if ((vnd_userial.fd >= 0) && (result = close(vnd_userial.fd)) < 0)
        AICBTDBG(LOGERROR, "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.fd, result);
    if (vnd_userial.thread_uart_id != -1)
      pthread_join(vnd_userial.thread_uart_id, NULL);
}


void userial_send_close_signal(void)
{
    unsigned char close_signal = 1;
    ssize_t ret;
    AIC_NO_INTR(ret = write(vnd_userial.signal_fd[0], &close_signal, 1));
}

void userial_quene_close(void)
{
    RtbQueueFree(vnd_userial.data_order);
    RtbQueueFree(vnd_userial.recv_data);
    RtbQueueFree(vnd_userial.send_data);
}

void close_with_hci_reset(void)
{
    uint8_t hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
    int i = 0;
    ALOGD("%s, start send hci reset command", __func__);
    upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
    upio_set(UPIO_BT_WAKE, UPIO_ASSERT, 1);

    close_state = 0;
    h4_int_transmit_data(hci_reset, sizeof(hci_reset));

    for (i = 0; i < 5; i++) {
        if (close_state == 1) {
            ALOGD("%s, hci reset done", __func__);
            upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
            close_state = -1;
            return;
        }
        usleep(100000);
    }
    upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
    AICBTDBG(LOGINFO, "%s, send hci reset command timeout", __func__);
}

/*******************************************************************************
**
** Function        userial_vendor_close
**
** Description     Conduct vendor-specific close work
**
** Returns         None
**
*******************************************************************************/
void userial_vendor_close(void)
{
    close_with_hci_reset();

    if (vnd_userial.fd == -1)
        return;

    if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H5)) {
#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
        /* de-assert bt_wake BEFORE closing port */
        ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
#endif
        //h5_int_interface->h5_int_cleanup();

    }

    vnd_userial.thread_running = false;
#ifdef CONFIG_SCO_OVER_HCI
    if (sco_cb.thread_sco_running) {
        sco_cb.thread_sco_running = false;
        //unsigned char close_signal = 1;
        //ssize_t ret;
        //AIC_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
        //pthread_join(sco_cb.thread_socket_sco_id, NULL);
    }
#endif
//    Heartbeat_cleanup();
    AIC_btservice_destroyed();
    userial_send_close_signal();
    userial_uart_close();
    userial_socket_close();
    userial_quene_close();
#if 0
    if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H5)) {
        h5_int_interface->h5_int_cleanup();
    }
#endif

    vnd_userial.fd = -1;
    vnd_userial.btdriver_state = false;
    vnd_userial.is_hardware_err = false;
#ifdef CONFIG_SCO_OVER_HCI
    pthread_mutex_destroy(&sco_cb.sco_recv_mutex);
    pthread_cond_destroy(&sco_cb.sco_recv_cond);
    pthread_mutex_destroy(&sco_cb.msbc_recv_mutex);
    pthread_mutex_destroy(&sco_cb.msbc_send_mutex);
    pthread_cond_destroy(&sco_cb.msbc_send_cond);
    RtbQueueFree(sco_cb.recv_sco_data);
    RtbQueueFree(sco_cb.send_sco_data);
    RtbQueueFree(sco_cb.recv_msbc_dec_data);
    RtbQueueFree(sco_cb.send_msbc_enc_data);

    //sbc_finish(&sco_cb.sbc_enc);
    //sbc_finish(&sco_cb.sbc_dec);
#if AIC_SCO_UART_SUPPORT
    AICBTDBG(LOGINFO, "%s \n", __func__);
    if (btif_aic_sco_cb.fd_t != 0){
      close(btif_aic_sco_cb.fd_t);
    }
    RtbQueueFree(btif_aic_sco_cb.data_msg_queue );
    RtbQueueFree(btif_aic_sco_cb.snd_recv_msg_queue);
    pthread_mutex_destroy(&btif_aic_sco_cb.worker_recv_mutex);
    pthread_cond_destroy(&btif_aic_sco_cb.worker_thread_cond);
#endif
#endif
    AICBTDBG(LOGINFO, "%s finish", __func__);
}

/*******************************************************************************
**
** Function        userial_vendor_set_baud
**
** Description     Set new baud rate
**
** Returns         None
**
*******************************************************************************/
void userial_vendor_set_baud(uint8_t userial_baud)
{
    uint32_t tcio_baud;

    userial_to_tcio_baud(userial_baud, &tcio_baud);

    cfsetospeed(&vnd_userial.termios, tcio_baud);
    cfsetispeed(&vnd_userial.termios, tcio_baud);
    tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios);
}

/*******************************************************************************
**
** Function        userial_vendor_ioctl
**
** Description     ioctl inteface
**
** Returns         None
**
*******************************************************************************/
void userial_vendor_ioctl(userial_vendor_ioctl_op_t op, void *p_data)
{
    AIC_UNUSED(p_data);
    switch (op) {
#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
        case USERIAL_OP_ASSERT_BT_WAKE:
            VNDUSERIALDBG("## userial_vendor_ioctl: Asserting BT_Wake##");
            ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
            break;

        case USERIAL_OP_DEASSERT_BT_WAKE:
            VNDUSERIALDBG("## userial_vendor_ioctl: De-asserting BT_Wake##");
            ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
            break;

        case USERIAL_OP_GET_BT_WAKE_STATE:
            ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_GET_ST, p_data);
            break;
#endif  //  (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)

        default:
            break;
    }
}

/*******************************************************************************
**
** Function        userial_set_port
**
** Description     Configure UART port name
**
** Returns         0 : Success
**                 Otherwise : Fail
**
*******************************************************************************/
int userial_set_port(char *p_conf_name, char *p_conf_value, int param)
{
    AIC_UNUSED(p_conf_name);
    AIC_UNUSED(param);
    strcpy(vnd_userial.port_name, p_conf_value);

    return 0;
}

/*******************************************************************************
**
** Function        userial_vendor_set_hw_fctrl
**
** Description     Conduct vendor-specific close work
**
** Returns         None
**
*******************************************************************************/
void userial_vendor_set_hw_fctrl(uint8_t hw_fctrl)
{
    struct termios termios_old;

    if (vnd_userial.fd == -1) {
        AICBTDBG(LOGERROR, "vnd_userial.fd is -1");
        return;
    }

    tcgetattr(vnd_userial.fd, &termios_old);
    if (hw_fctrl) {
        if (termios_old.c_cflag & CRTSCTS) {
            AICBTDBG(LOGINFO, "userial_vendor_set_hw_fctrl already hw flowcontrol on");
            return;
        } else {
            termios_old.c_cflag |= CRTSCTS;
            tcsetattr(vnd_userial.fd, TCSANOW, &termios_old);
            AICBTDBG(LOGINFO, "userial_vendor_set_hw_fctrl set hw flowcontrol on");
        }
    } else {
        if (termios_old.c_cflag & CRTSCTS) {
            termios_old.c_cflag &= ~CRTSCTS;
            tcsetattr(vnd_userial.fd, TCSANOW, &termios_old);
            return;
        } else {
            AICBTDBG(LOGINFO, "userial_vendor_set_hw_fctrl set hw flowcontrol off");
            return;
        }
    }
}

static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length) {
    assert(data != NULL);
    assert(total_length > 0);

    uint16_t length = total_length;
    uint16_t transmitted_length = 0;
    while (length > 0 && vnd_userial.btdriver_state) {
        ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
        switch (ret) {
            case -1:
                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                vnd_userial.btdriver_state = false;
                userial_send_hw_error();
                vnd_userial.is_hardware_err = true;
                goto done;
            case 0:
                // If we wrote nothing, don't loop more because we
                // can't go to infinity or beyond, ohterwise H5 can resend data
                ALOGE("%s, ret %zd", __func__, ret);
                goto done;
            case -EFAULT:
            case -EINVAL:
                // If we wrote nothing, don't loop more because we
                // can't go to infinity or beyond, ohterwise H5 can resend data
                ALOGE("%s, ret %zd", __func__, ret);
                vnd_userial.btdriver_state = false;
                userial_send_hw_error();
                vnd_userial.is_hardware_err = true;
                goto done;
            default:
                transmitted_length += ret;
                length -= ret;
                break;
        }
    }

done:
    return transmitted_length;
}



#ifdef AIC_HANDLE_EVENT
static void userial_send_cmd_to_controller(unsigned char *recv_buffer, int total_length)
{
    if (aicbt_transtype & AICBT_TRANS_H4) {
        h4_int_transmit_data(recv_buffer, total_length);
    } else {
        h5_int_interface->h5_send_cmd(DATA_TYPE_COMMAND, &recv_buffer[1], (total_length - 1));
    }
}
#endif

static void userial_send_acl_to_controller(unsigned char *recv_buffer, int total_length)
{
    if (aicbt_transtype & AICBT_TRANS_H4) {
        h4_int_transmit_data(recv_buffer, total_length);
    } else {
        h5_int_interface->h5_send_acl_data(DATA_TYPE_ACL, &recv_buffer[1], (total_length - 1));
    }
}

static void userial_send_sco_to_controller(unsigned char *recv_buffer, int total_length)
{
    if (aicbt_transtype & AICBT_TRANS_H4) {
        h4_int_transmit_data(recv_buffer, total_length);
    } else {
        h5_int_interface->h5_send_sco_data(DATA_TYPE_SCO, &recv_buffer[1], (total_length - 1));
    }
}


#ifdef CONFIG_SCO_OVER_HCI
#if AIC_SCO_UART_SUPPORT
#if AIC_PLC_EN
static void btif_aic_sco_plc_deinit(void)
{
  aic_plc_en = false;
  ALOGE("%s,aic_plc_en = %d", __func__,aic_plc_en);
}

static void btif_aic_sco_plc_init(uint8_t len)
{
  int sample = 8;
  float msec = 7.5;

  if (!aic_plc_en) {
    aic_plc_en = true;
    if(btif_aic_sco_cb.air_mode == 0x03) {
        sample = 16;
        msec = (float)len/32 ;
    } else {
        sample = 8;
        msec = (float)len/16;
    }
    ALOGE("%s,len = %d, sample %d, msec %f", __func__,len,sample,msec);
    g711plc_construct(&lc, sample,msec);
  }
}
#endif

static void *worker_thread(void *arg)
{
    AIC_UNUSED(arg);
    prctl(PR_SET_NAME, (unsigned long)"worker_thread", 0, 0, 0);
    BT_HDR* p_buf = (BT_HDR*)malloc(sizeof(BT_HDR) + 4);
    BT_HDR* p_buf_1 = (BT_HDR*)malloc(sizeof(BT_HDR) + 4);

    p_buf_1->data[0] = SET_SELECT_MSBC;
    p_buf->data[0] = SET_UART_SCO_OPEN;
    ALOGE("%s\n", __func__);
    if(btif_aic_sco_cb.air_mode == 0x03) {
    write(btif_aic_sco_cb.fd_t,p_buf_1->data, 1);
    }
    write(btif_aic_sco_cb.fd_t,p_buf->data, 1);
    btif_aic_sco_state = BTIF_AIC_SCO_STATE_ON;
    free(p_buf);
    free(p_buf_1);
    ALOGD("worker_thread start");
    while (btif_aic_sco_cb.worker_thread_running) {
        uint8_t temp_ram[512];
        uint16_t handle;
        uint8_t len;
        int rd_len,i;
        BT_HDR* p_buf;
        AIC_BUFFER* snd_recv_buf[20];
        uint16_t errflag = 0;
        int ret_size;
        memset(temp_ram,0,512);


        AIC_BUFFER* p_msg;
        pthread_mutex_lock(&btif_aic_sco_cb.worker_recv_mutex);
        while(RtbQueueIsEmpty(btif_aic_sco_cb.data_msg_queue) && sco_cb.thread_sco_running) {
            pthread_cond_wait(&btif_aic_sco_cb.worker_thread_cond, &btif_aic_sco_cb.worker_recv_mutex);
        }
        pthread_mutex_unlock(&btif_aic_sco_cb.worker_recv_mutex);
        p_msg = RtbDequeueHead(btif_aic_sco_cb.data_msg_queue);
        if(!p_msg)
            continue;
        if (btif_aic_sco_cb.fd_t) {
            errflag = ((0x3000 & (((uint16_t)p_msg->Data[2])<<8 | (uint16_t)p_msg->Data[1]))>>12);
            handle = 0x0fff & (((uint16_t)p_msg->Data[2])<<8 | (uint16_t)p_msg->Data[1]);
            len = p_msg->Data[3];
#if AIC_PLC_EN
            btif_aic_sco_plc_init(len);
            memcpy(temp_ram,(p_msg->Data+4),len);
            if (errflag){
              ALOGE("errflag %d \n", errflag);
              plc((short *)temp_ram, &lc, 1, 1);
            }else{
              plc((short *)temp_ram, &lc, 0, 1);
            }
#endif
            ret_size = write(btif_aic_sco_cb.fd_t,temp_ram, len);
            //ALOGE("%s,len:%d,ret_size:%d\n", __func__, len,(int)ret_size);
            if(btif_aic_sco_cb.snd_sco_count>0)
                btif_aic_sco_cb.snd_sco_count--;
        }
        RtbFree(p_msg);

        if (btif_aic_sco_cb.fd_t) {
          //ALOGE("%s,snd_recv_msg_queue len %ld\n", __func__,RtbGetQueueLen(btif_aic_sco_cb.snd_recv_msg_queue));
          if (btif_aic_sco_cb.snd_sco_count==0 ){
            p_buf = (BT_HDR*)malloc(sizeof(BT_HDR) + 2048);
            if ((rd_len = read(btif_aic_sco_cb.fd_t,p_buf->data, 2048)) <= 0) {
              //ALOGE("%s,rd error\n", __func__);
              free(p_buf);
              continue;
            }
            btif_aic_sco_cb.snd_sco_count = p_buf->data[0];
            //ALOGE("%s,rd_len %d,count %d,len %d,fmt %d\n", __func__,rd_len,btif_aic_sco_cb.snd_sco_count,len,sco_cb.codec_para.output_format);
            for(i=0; i<btif_aic_sco_cb.snd_sco_count; i++){
              snd_recv_buf[i]= RtbAllocate(len + 4, 0);
              if(snd_recv_buf[i]!=NULL){
                  snd_recv_buf[i]->Data[0]= DATA_TYPE_SCO;
                  snd_recv_buf[i]->Data[1]= (uint8_t)(handle&0x00ff);
                  snd_recv_buf[i]->Data[2]= (uint8_t)((handle&0xff00)>>8);
                  snd_recv_buf[i]->Data[3]= len;
                  memcpy(&snd_recv_buf[i]->Data[4],(p_buf->data+1+(len*i)),len);
                  RtbAddTail(snd_recv_buf[i], len + 4);
                  if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_MSBC) {
                      //ALOGE("sco len %d,%x,%x,%x,%x", h4_read_length,h4_read_buffer[0],h4_read_buffer[1],h4_read_buffer[2],h4_read_buffer[3]);
                      pthread_mutex_lock(&sco_cb.msbc_send_mutex);
                      RtbQueueTail(sco_cb.send_msbc_enc_data, snd_recv_buf[i]);
                      pthread_cond_signal(&sco_cb.msbc_send_cond);
                      pthread_mutex_unlock(&sco_cb.msbc_send_mutex);
                  } else {
                      RtbQueueTail(btif_aic_sco_cb.snd_recv_msg_queue, snd_recv_buf[i]);
                  }
              }
            }
            free(p_buf);
          }
        }

    }
    ALOGD("worker_thread exit");

    {
      BT_HDR* p_buf = (BT_HDR*)malloc(sizeof(BT_HDR) + 4);
      p_buf->data[0] = SET_UART_SCO_CLOSE;
      ALOGE("%s\n", __func__);
      btif_aic_sco_state = BTIF_AIC_SCO_STATE_OFF;
      write(btif_aic_sco_cb.fd_t,p_buf->data, 1);
      free(p_buf);
#if AIC_PLC_EN
      btif_aic_sco_plc_deinit();
#endif
      btif_aic_sco_cb.snd_sco_count = 0;
    }
    return NULL;
}
static void worker_thread_stop(void)
{
    ALOGD("%s", __func__);
    pthread_mutex_lock(&btif_aic_sco_cb.worker_recv_mutex);
    if (btif_aic_sco_cb.worker_thread_running) {
        btif_aic_sco_cb.worker_thread_running = false;
        pthread_cond_signal(&btif_aic_sco_cb.worker_thread_cond);
    } else {
        pthread_mutex_unlock(&btif_aic_sco_cb.worker_recv_mutex);
        return;
    }
    pthread_mutex_unlock(&btif_aic_sco_cb.worker_recv_mutex);

    if (btif_aic_sco_cb.worker_thread != -1) {
        pthread_join(btif_aic_sco_cb.worker_thread, NULL);
        btif_aic_sco_cb.worker_thread = -1;
    }
}

#endif

//receive sco encode or non-encode data over hci, we need to decode msbc data to pcm, and send it to sco audio hal
static void *userial_recv_sco_thread(void *arg)
{
    AIC_UNUSED(arg);
    AIC_BUFFER *skb_sco_data;
    unsigned char dec_data[480];
    unsigned char pcm_data[960];
    int index = 0;
    //uint16_t sco_packet_len = 60;
    uint8_t *p_data = NULL;
    int res = 0;
    size_t writen = 0;
    prctl(PR_SET_NAME, (unsigned long)"userial_recv_sco_thread", 0, 0, 0);
    sco_cb.pcm_dec_seq = -1;
    sco_cb.pcm_dec_frame = 0;
#ifdef CONFIG_SCO_MSBC_PLC
    unsigned char plc_data[480];
    struct PLC_State plc_state;
    InitPLC(&plc_state);
#endif
    /*
    FILE *file;
    unsigned char enc_data[60];
    file = fopen("/data/misc/bluedroid/sco_capture.raw", "rb");
    FILE *file2;
    file2 = fopen("/data/misc/bluedroid/sco_capture.pcm", "wb");
    if (!file) {
        ALOGE("Unable to create file");
        return NULL;
    }
    */
    //RtbEmptyQueue(sco_cb.recv_sco_data);
    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
    while (RtbGetQueueLen(sco_cb.recv_sco_data) > 60) {
        AIC_BUFFER *sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
        if (sco_data)
            RtbFree(sco_data);
    }
    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);

    ALOGD("userial_recv_sco_thread start");
    while (sco_cb.thread_recv_sco_running) {
        pthread_mutex_lock(&sco_cb.sco_recv_mutex);
        while (RtbQueueIsEmpty(sco_cb.recv_sco_data) && sco_cb.thread_sco_running) {
            pthread_cond_wait(&sco_cb.sco_recv_cond, &sco_cb.sco_recv_mutex);
        }
        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
        skb_sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
        if (!skb_sco_data)
            continue;
        p_data = skb_sco_data->Data;

        switch (sco_cb.codec_para.input_format) {
        case ESCO_CODING_FORMAT_LINEAR:  // PCM raw data
        case ESCO_CODING_FORMAT_CVSD:    // Cvsd codec
            break;
        case ESCO_CODING_FORMAT_MSBC: {
                uint8_t seq = (p_data[1] >> 4) & 0x0F;
                uint32_t last_dec_frame = sco_cb.pcm_dec_frame;
                if (sco_cb.pcm_dec_seq == -1) {
                    uint8_t step = 0;
                    sco_cb.pcm_dec_seq = (int8_t)seq;
                    step += (seq & 0x03)/2;
                    step += ((seq >> 2) & 0x03) / 2;
                    sco_cb.pcm_dec_frame += step;
                } else {
                    do {
                        if(seq != 0x00 && seq != 0x03 && seq != 0x0c && seq != 0x0f ){
                            ALOGE("lost all frame may use the plc function one time");
                            sco_cb.pcm_dec_frame++;
                            break;
                        }
                        sco_cb.pcm_dec_seq = (uint8_t)((btui_msbc_h2[(++sco_cb.pcm_dec_frame) % 4] >> 12) & 0x0F);
                        if (sco_cb.pcm_dec_frame - last_dec_frame > 3) {
                            // fix package loss.
                            ALOGE("lost frame: %d, may use the plc function", (sco_cb.pcm_dec_frame - last_dec_frame));
                            break;
                        }
                    } while (sco_cb.pcm_dec_seq != seq);

                    if ((last_dec_frame + 1) != sco_cb.pcm_dec_frame && (sco_cb.pcm_dec_frame - last_dec_frame < 4)) {
#ifdef CONFIG_SCO_MSBC_PLC
                        uint8_t lost_frame = sco_cb.pcm_dec_frame - last_dec_frame - 1;
                        int i = 0;
                        for (i = 0; i < lost_frame; i++) {
                            sbc_decode(&sco_cb.sbc_dec, indices0, 58, dec_data, 240, &writen);
                            PLC_bad_frame(&plc_state, (short*)dec_data, (short*)plc_data);
                            memcpy(&pcm_data[240 * index], plc_data, 240);
                            //index = (index + 1) % 4;
                            index ++;
                            if(index == 1) {
                                #if 1
                                AIC_BUFFER* skb_msbc_dec_data;
                            
                                skb_msbc_dec_data = RtbAllocate(244, 0);
                                memcpy(skb_msbc_dec_data->Data+4, pcm_data, 240);
                                skb_msbc_dec_data->Data[0] = DATA_TYPE_SCO;
                                skb_msbc_dec_data->Data[1] = (uint8_t)(sco_cb.sco_handle & 0x00ff);
                                skb_msbc_dec_data->Data[2] = (uint8_t)((sco_cb.sco_handle & 0xff00)>>8);
                                skb_msbc_dec_data->Data[3] = 240;
                                RtbAddTail(skb_msbc_dec_data, 244);
                                pthread_mutex_lock(&sco_cb.msbc_recv_mutex);
                                RtbQueueTail(sco_cb.recv_msbc_dec_data, skb_msbc_dec_data);
                                pthread_mutex_unlock(&sco_cb.msbc_recv_mutex);
                                #endif
                                ALOGE("auto add num %d lost 240",i);
                                index = 0;
                            }

                        }
#else
                        uint8_t lost_frame = sco_cb.pcm_dec_frame - last_dec_frame - 1;
                        int i = 0;
                        for (i = 0; i < lost_frame; i++) {
                            memset(&pcm_data[240 * index], 0, 240);
                            index ++;
                            if(index == 1) {
                                AIC_BUFFER* skb_msbc_dec_data;
                                skb_msbc_dec_data = RtbAllocate(244, 0);
                                memcpy(skb_msbc_dec_data->Data+4, pcm_data, 240);
                                skb_msbc_dec_data->Data[0] = DATA_TYPE_SCO;
                                skb_msbc_dec_data->Data[1] = (uint8_t)(sco_cb.sco_handle & 0x00ff);
                                skb_msbc_dec_data->Data[2] = (uint8_t)((sco_cb.sco_handle & 0xff00)>>8) | 0x20;//add sco errflag
                                skb_msbc_dec_data->Data[3] = 240;
                                RtbAddTail(skb_msbc_dec_data, 244);
                                pthread_mutex_lock(&sco_cb.msbc_recv_mutex);
                                RtbQueueTail(sco_cb.recv_msbc_dec_data, skb_msbc_dec_data);
                                pthread_mutex_unlock(&sco_cb.msbc_recv_mutex);
                                ALOGE("auto add num %d lost 240",i);
                                index = 0;
                            }
                        }
#endif
                    }
                }

                res = sbc_decode(&sco_cb.sbc_dec, (p_data + 2), 58, dec_data, 240, &writen);
                if (res > 0) {
#ifdef CONFIG_SCO_MSBC_PLC
                    PLC_good_frame(&plc_state, (short*)dec_data, (short*)plc_data);
                    memcpy(&pcm_data[240 * index], plc_data, 240);
#else
                    memcpy(&pcm_data[240 * index], dec_data, 240);
#endif
                    //if (fwrite(dec_data, 240, 1, file2) != 240) {
                    //    ALOGE("Error capturing sample");
                    //}
                    index ++;
                    if(index == 1) {
                        #if 1
                        AIC_BUFFER* skb_msbc_dec_data;
                    
                        skb_msbc_dec_data = RtbAllocate(244, 0);
                        memcpy(skb_msbc_dec_data->Data+4, pcm_data, 240);
                        skb_msbc_dec_data->Data[0] = DATA_TYPE_SCO;
                        skb_msbc_dec_data->Data[1] = (uint8_t)(sco_cb.sco_handle & 0x00ff);
                        skb_msbc_dec_data->Data[2] = (uint8_t)((sco_cb.sco_handle & 0xff00)>>8);
                        skb_msbc_dec_data->Data[3] = 240;
                        RtbAddTail(skb_msbc_dec_data, 244);
                        pthread_mutex_lock(&sco_cb.msbc_recv_mutex);
                        RtbQueueTail(sco_cb.recv_msbc_dec_data, skb_msbc_dec_data);
                        pthread_mutex_unlock(&sco_cb.msbc_recv_mutex);
                        #endif
                        //ALOGE("send 240");
                        index = 0;
                    }

                } else {
                    ALOGE("msbc decode fail! May use PLC function");
#ifdef CONFIG_SCO_MSBC_PLC
                    sbc_decode(&sco_cb.sbc_dec, indices0, 58, dec_data, 240, &writen);
                    PLC_bad_frame(&plc_state, (short*)dec_data, (short*)plc_data);
                    memcpy(&pcm_data[240 * index], plc_data, 240);
                    index++;
                    if(index == 1) {
                        #if 1
                        AIC_BUFFER* skb_msbc_dec_data;
                    
                        skb_msbc_dec_data = RtbAllocate(244, 0);
                        memcpy(skb_msbc_dec_data->Data+4, pcm_data, 240);
                        skb_msbc_dec_data->Data[0] = DATA_TYPE_SCO;
                        skb_msbc_dec_data->Data[1] = (uint8_t)(sco_cb.sco_handle & 0x00ff);
                        skb_msbc_dec_data->Data[2] = (uint8_t)((sco_cb.sco_handle & 0xff00)>>8);
                        skb_msbc_dec_data->Data[3] = 240;
                        RtbAddTail(skb_msbc_dec_data, 244);
                        pthread_mutex_lock(&sco_cb.msbc_recv_mutex);
                        RtbQueueTail(sco_cb.recv_msbc_dec_data, skb_msbc_dec_data);
                        pthread_mutex_unlock(&sco_cb.msbc_recv_mutex);
                        #endif
                        //ALOGE("send 240");
                        index = 0;
                    }
#else
                    memset(&pcm_data[240 * index], 0, 240);
                    index++;
                    if(index == 1) {
                        AIC_BUFFER* skb_msbc_dec_data;
                        skb_msbc_dec_data = RtbAllocate(244, 0);
                        memcpy(skb_msbc_dec_data->Data+4, pcm_data, 240);
                        skb_msbc_dec_data->Data[0] = DATA_TYPE_SCO;
                        skb_msbc_dec_data->Data[1] = (uint8_t)(sco_cb.sco_handle & 0x00ff);
                        skb_msbc_dec_data->Data[2] = (uint8_t)((sco_cb.sco_handle & 0xff00)>>8)| 0x20;//add sco errflag
                        skb_msbc_dec_data->Data[3] = 240;
                        RtbAddTail(skb_msbc_dec_data, 244);
                        pthread_mutex_lock(&sco_cb.msbc_recv_mutex);
                        RtbQueueTail(sco_cb.recv_msbc_dec_data, skb_msbc_dec_data);
                        pthread_mutex_unlock(&sco_cb.msbc_recv_mutex);
                        //ALOGE("send 240");
                        index = 0;
                    }
#endif
                }
            }
            break;
        default:
            ALOGE("Unsupport coding format: 0x%02X", sco_cb.codec_para.input_format);
            break;
        }
        RtbFree(skb_sco_data);
    }
    ALOGD("userial_recv_sco_thread exit");
    RtbEmptyQueue(sco_cb.recv_sco_data);
    return NULL;
}

static void *userial_send_sco_thread(void *arg)
{
    AIC_UNUSED(arg);
    unsigned char enc_data[240];
    unsigned char pcm_data[960 * 2];
    unsigned char send_data[240];
    int writen = 0;
    int num_read;
    prctl(PR_SET_NAME, (unsigned long)"userial_send_sco_thread", 0, 0, 0);
    sco_cb.pcm_enc_seq = 0;
    int i;
    int need_read = sco_cb.sco_packet_len;

    if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_MSBC)
        need_read = 240;

    #if 0
    //when start sco send thread, first send 6 sco data to controller
    if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_CVSD) {
        if(aicbt_transtype & AICBT_TRANS_UART){
            
        }else{
            
        }
        memset(pcm_data, 0, (48*6));
        for (i = 0; i < 6; i++) {
            send_data[0] = DATA_TYPE_SCO;
            send_data[3] = 48;
            *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
            memcpy(&send_data[4], &pcm_data[i*48], 48);
            userial_send_sco_to_controller(send_data, 52);
        }
    }
    #endif
    ALOGD("userial_send_sco_thread start");
    while (sco_cb.thread_send_sco_running) {
        switch (sco_cb.codec_para.output_format) {
            case ESCO_CODING_FORMAT_LINEAR:
                break;
            case ESCO_CODING_FORMAT_CVSD:
                break;
            case ESCO_CODING_FORMAT_MSBC:
                {
                    AIC_BUFFER* skb_msbc_enc_data;
                    pthread_mutex_lock(&sco_cb.msbc_send_mutex);
                    while(RtbQueueIsEmpty(sco_cb.send_msbc_enc_data) && sco_cb.thread_sco_running) {
                        pthread_cond_wait(&sco_cb.msbc_send_cond, &sco_cb.msbc_send_mutex);
                    }
                    pthread_mutex_unlock(&sco_cb.msbc_send_mutex);
                    skb_msbc_enc_data = RtbDequeueHead(sco_cb.send_msbc_enc_data);
                    if(!skb_msbc_enc_data)
                        continue;
                    memcpy(&pcm_data[num_read],skb_msbc_enc_data->Data+4,240);
                    num_read += 240;
                    if (num_read == 480) {
                        num_read = 0;
                        for(i = 0; i < 2; i++) {
                            if(sbc_encode(&sco_cb.sbc_enc, &pcm_data[240*i], 240, &enc_data[i*60 +2], 58, (ssize_t *)&writen) <= 0) {
                                ALOGE("sbc encode error!");
                            }
                            else {
                                *(uint16_t*)(&(enc_data[i*60])) = btui_msbc_h2[sco_cb.pcm_enc_seq];
                                sco_cb.pcm_enc_seq = (sco_cb.pcm_enc_seq+1) % 4;
                                enc_data[i*60 + 59] = 0x00;    //padding
                            }
                        }
                        if(aicbt_transtype & AICBT_TRANS_UART){
                            for(i = 0; i < 2; i++){
                                send_data[0] = DATA_TYPE_SCO;
                                send_data[3] = 60;
                                *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
                                memcpy(&send_data[4], &enc_data[i*60], sco_cb.sco_packet_len);
                                userial_send_sco_to_controller(send_data, sco_cb.sco_packet_len + 4);
                            }
                        }else{
                            for(i = 0; i < 5; i++) {
                                send_data[0] = DATA_TYPE_SCO;
                                send_data[3] = 24;
                                *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
                                memcpy(&send_data[4], &enc_data[i*24], 24);
                                userial_send_sco_to_controller(send_data, 28);
                            }
                        }
                    }
                    RtbFree(skb_msbc_enc_data);
                }
                break;
            default:
                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.output_format);
                break;
        }
    }
    ALOGD("userial_send_sco_thread exit");
    return NULL;
}

static void userial_sco_send_socket_stop()
{
    ALOGD("%s", __func__);
    pthread_mutex_lock(&sco_cb.msbc_send_mutex);
    if (sco_cb.thread_send_sco_running) {
        sco_cb.thread_send_sco_running = false;
        pthread_cond_signal(&sco_cb.msbc_send_cond);
    } else {
        pthread_mutex_unlock(&sco_cb.msbc_send_mutex);
        return;
    }
    pthread_mutex_unlock(&sco_cb.msbc_send_mutex);

    if (sco_cb.thread_send_sco_id != -1) {
        pthread_join(sco_cb.thread_send_sco_id, NULL);
        sco_cb.thread_send_sco_id = -1;
    }
}

static void userial_sco_recv_socket_stop()
{
    ALOGD("%s", __func__);
    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
    if (sco_cb.thread_recv_sco_running) {
        sco_cb.thread_recv_sco_running = false;
        pthread_cond_signal(&sco_cb.sco_recv_cond);
    } else {
        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
        return;

    }
    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);

    if (sco_cb.thread_recv_sco_id != -1) {
        pthread_join(sco_cb.thread_recv_sco_id, NULL);
        sco_cb.thread_recv_sco_id = -1;
    }

}

static void userial_sco_socket_stop()
{
    ALOGD("%s", __func__);
    userial_sco_send_socket_stop();
    userial_sco_recv_socket_stop();

    RtbEmptyQueue(sco_cb.recv_sco_data);
    RtbEmptyQueue(sco_cb.send_sco_data);
    RtbEmptyQueue(sco_cb.recv_msbc_dec_data);
    RtbEmptyQueue(sco_cb.send_msbc_enc_data);

#if AIC_SCO_UART_SUPPORT
    worker_thread_stop();
#endif
}

static void userial_sco_ctrl_skt_handle(uint8_t cmd)
{
    ALOGE("%s, cmd = %d, msbc_used = %d", __func__, cmd, sco_cb.codec_para.output_format );
    switch (cmd) {
        case SCO_CTRL_CMD_OUT_START:
        {
            pthread_attr_t thread_attr;
            pthread_attr_init(&thread_attr);
            pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
            sco_cb.thread_send_sco_running = true;
            if(pthread_create(&sco_cb.thread_send_sco_id, &thread_attr, userial_send_sco_thread, NULL)!= 0 )
            {
                ALOGE("pthread_create : %s", strerror(errno));
            }
        }
        break;

        case SCO_CTRL_CMD_IN_START:
        {
            pthread_attr_t thread_attr;
            pthread_attr_init(&thread_attr);
            pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
            sco_cb.thread_recv_sco_running = true;
            if(pthread_create(&sco_cb.thread_recv_sco_id, &thread_attr, userial_recv_sco_thread, NULL)!= 0 )
            {
                ALOGE("pthread_create : %s", strerror(errno));
            }
        }
        break;

        case SCO_CTRL_CMD_OUT_STOP:
            userial_sco_send_socket_stop();
        break;

        case SCO_CTRL_CMD_IN_STOP:
            userial_sco_recv_socket_stop();
        break;

        case SCO_CTRL_CMD_CLOSE:
            userial_sco_socket_stop();
        break;

        default:

        break;
    }
}

#endif

struct adv_tracking_handle_t {
    uint8_t  state;
    uint8_t  evt[40];
    uint8_t  address[6];
    uint64_t timestamp;
};

enum adv_tracking_state_t {
    ADV_TRACKING_IDLE,
    ADV_TRACKING_SET,
    ADV_TRACKING_ON,
    ADV_FILTERED,
    ADV_TRACKING_OFF,
};

static struct adv_tracking_handle_t adv_tracking = {
    .state = ADV_TRACKING_IDLE,
    .timestamp = 0,
    .evt = {
        0x04, 0xff, 0x25, 0x56, 0x11, 0x00, 0x01, 0x8a,
        0x4e, 0x0f, 0x07, 0xda, 0x78, 0x00, 0x80, 0xd6,
        0x00, 0x00, 0x14, 0x02, 0x01, 0x06, 0x03, 0x19,
        0x80, 0x01, 0x03, 0x02, 0x12, 0x18, 0x08, 0x09,
        0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x00},
};

static uint64_t get_timestamp(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000LL * 1000LL + tv.tv_usec;
}

#ifdef AIC_HANDLE_CMD
static bool userial_handle_cmd(unsigned char *recv_buffer, int total_length)
{
	bool ret = false;
    AIC_UNUSED(total_length);
    uint16_t opcode = *(uint16_t*)recv_buffer;
    uint16_t scan_int, scan_win;
    static uint16_t voice_settings;
    char prop_value[100];
    AICBTDBG(LOGDEBUG, "%s opcode:%x\r\n", __func__, opcode);
    switch (opcode) {
        case HCI_BLE_WRITE_SCAN_PARAMS :
            scan_int = *(uint16_t*)&recv_buffer[4];
            scan_win = *(uint16_t*)&recv_buffer[6];
            if (scan_win > 20){
                if ((scan_int/scan_win) > 2) {
                    *(uint16_t*)&recv_buffer[4] = (scan_int * 20) / scan_win;
                    *(uint16_t*)&recv_buffer[6] = 20;
                } else {
                    *(uint16_t*)&recv_buffer[4] = 40;
                    *(uint16_t*)&recv_buffer[6] = 20;
                }
            } else if (scan_win == scan_int) {
                *(uint16_t*)&recv_buffer[4] = (scan_int * 5) & 0xFE;
            } else if ((scan_int/scan_win) <= 2) {
                *(uint16_t*)&recv_buffer[4] = (scan_int * 3) & 0xFE;
            }
            break;

        case HCI_LE_SET_EXTENDED_SCAN_PARAMETERS:
            scan_int = *(uint16_t*)&recv_buffer[7];
            scan_win = *(uint16_t*)&recv_buffer[9];
            if (scan_win > 20){
                if ((scan_int/scan_win) > 2) {
                    *(uint16_t*)&recv_buffer[7] = (scan_int * 20) / scan_win;
                    *(uint16_t*)&recv_buffer[9] = 20;
                } else {
                    *(uint16_t*)&recv_buffer[7] = 40;
                    *(uint16_t*)&recv_buffer[9] = 20;
                }
            } else if (scan_win == scan_int) {
                *(uint16_t*)&recv_buffer[7] = (scan_int * 5) & 0xFE;
            } else if ((scan_int/scan_win) <= 2) {
                *(uint16_t*)&recv_buffer[9] = (scan_int * 3) & 0xFE;
            }
            break;

        case HCI_LE_EXTENDED_CREATE_CONNECTION:
            ALOGD("Origin LE_EXTENDED_CREATE_CONN interval, 1M: 0x%04x/0x%04x, 2M: 0x%04x/0x%04x, Coded: 0x%04x/0x%04x",
                    *(uint16_t*)&recv_buffer[17], *(uint16_t*)&recv_buffer[19],
                    *(uint16_t*)&recv_buffer[33], *(uint16_t*)&recv_buffer[35],
                    *(uint16_t*)&recv_buffer[49], *(uint16_t*)&recv_buffer[51]);

            *(uint16_t*)&recv_buffer[17] = 0x0006; // 1M Phy Connection Interval Min
            *(uint16_t*)&recv_buffer[19] = 0x000C; // 1M Phy Connection Interval Max

            *(uint16_t*)&recv_buffer[33] = 0x0006; // 2M Phy Connection Interval Min
            *(uint16_t*)&recv_buffer[35] = 0x000C; // 2M Phy Connection Interval Max

            *(uint16_t*)&recv_buffer[49] = 0x0006; // Coded Phy Connection Interval Min
            *(uint16_t*)&recv_buffer[51] = 0x000C; // Coded Phy Connection Interval Max

            ALOGD("Hooked LE_EXTENDED_CREATE_CONN interval, 1M: 0x%04x/0x%04x, 2M: 0x%04x/0x%04x, Coded: 0x%04x/0x%04x",
                    *(uint16_t*)&recv_buffer[17], *(uint16_t*)&recv_buffer[19],
                    *(uint16_t*)&recv_buffer[33], *(uint16_t*)&recv_buffer[35],
                    *(uint16_t*)&recv_buffer[49], *(uint16_t*)&recv_buffer[51]);
            break;

        case HCI_WRITE_VOICE_SETTINGS :
            voice_settings = *(uint16_t*)&recv_buffer[3];
            if (aicbt_transtype & AICBT_TRANS_USB) {
                userial_vendor_usb_ioctl(SET_ISO_CFG, &voice_settings);
            }
#ifdef CONFIG_SCO_OVER_HCI
            sco_cb.voice_settings = voice_settings;
#endif
            break;

#ifdef CONFIG_SCO_OVER_HCI
        case HCI_SETUP_ESCO_CONNECTION :
            ALOGD("%s, HCI_SETUP_ESCO_CONNECTION", __func__);
            sco_cb.voice_settings = *(uint16_t*)&recv_buffer[15];
            if (sco_cb.voice_settings & 0x0003) {
                sco_cb.codec_para.input_format  = ESCO_CODING_FORMAT_MSBC;
                sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_MSBC;
                sco_cb.codec_para.input_rate    = 16000;
                sco_cb.codec_para.output_rate   = 16000;
            } else {
                sco_cb.codec_para.input_format  = ESCO_CODING_FORMAT_LINEAR;
                sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_LINEAR;
                sco_cb.codec_para.input_rate    = 8000;
                sco_cb.codec_para.output_rate   = 8000;
            }
            break;
        case HCI_ENH_SETUP_ESCO_CONNECTION:
            ALOGD("%s, HCI_ENH_SETUP_ESCO_CONNECTION", __func__);
            memcpy(&sco_cb.esco_para, &recv_buffer[5], sizeof(sco_cb.esco_para));

            switch (sco_cb.esco_para.transmit_coding_format.coding_format) {
                case ESCO_CODING_FORMAT_ULAW:
                case ESCO_CODING_FORMAT_ALAW:
                case ESCO_CODING_FORMAT_CVSD:
                    if (sco_cb.esco_para.output_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
                        sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_LINEAR;
                    else
                        sco_cb.codec_para.output_format = sco_cb.esco_para.transmit_coding_format.coding_format;
                    sco_cb.codec_para.output_rate   = 8000;
                    break;
                case ESCO_CODING_FORMAT_MSBC: // stack bugs
                    sco_cb.esco_para.transmit_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
                case ESCO_CODING_FORMAT_TRANSPNT:
                    sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_MSBC;
                    sco_cb.codec_para.output_rate   = 16000;
                    break;
                default:
                    ALOGD("Unsupport transmit coding format");
                    break;
            }

            switch (sco_cb.esco_para.receive_coding_format.coding_format) {
                case ESCO_CODING_FORMAT_ULAW:
                case ESCO_CODING_FORMAT_ALAW:
                case ESCO_CODING_FORMAT_CVSD:
                    if (sco_cb.esco_para.input_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
                        sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_LINEAR;
                    else
                        sco_cb.codec_para.input_format = sco_cb.esco_para.receive_coding_format.coding_format;
                    sco_cb.codec_para.input_rate   = 8000;
                    break;
                case ESCO_CODING_FORMAT_MSBC: // stack bugs
                    sco_cb.esco_para.receive_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
                case ESCO_CODING_FORMAT_TRANSPNT:
                    sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_MSBC;
                    sco_cb.codec_para.input_rate   = 16000;
                    break;
                default:
                    ALOGD("Unsupport receive coding format");
                    break;
            }

            sco_cb.esco_para.input_data_path  = ESCO_DATA_PATH_HCI; // input data path, set to VOHCI
            sco_cb.esco_para.output_data_path = ESCO_DATA_PATH_HCI; // output data path, set to VOHCI
            memcpy(&recv_buffer[5], &sco_cb.esco_para, sizeof(sco_cb.esco_para));

            break;
        case HCI_ENH_ACCEPT_ESCO_CONNECTION:
            ALOGD("%s, HCI_ENH_ACCEPT_ESCO_CONNECTION", __func__);
            memcpy(&sco_cb.esco_para, &recv_buffer[9], sizeof(sco_cb.esco_para));

            switch (sco_cb.esco_para.transmit_coding_format.coding_format) {
                case ESCO_CODING_FORMAT_ULAW:
                case ESCO_CODING_FORMAT_ALAW:
                case ESCO_CODING_FORMAT_CVSD:
                    if (sco_cb.esco_para.output_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
                        sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_LINEAR;
                    else
                        sco_cb.codec_para.output_format = sco_cb.esco_para.transmit_coding_format.coding_format;
                    sco_cb.codec_para.output_rate   = 8000;
                    break;
                case ESCO_CODING_FORMAT_MSBC: // stack bugs
                    sco_cb.esco_para.transmit_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
                case ESCO_CODING_FORMAT_TRANSPNT:
                    sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_MSBC;
                    sco_cb.codec_para.output_rate   = 16000;
                    break;
                default:
                    ALOGD("Unsupport transmit coding format");
                    break;
            }

            switch (sco_cb.esco_para.receive_coding_format.coding_format) {
                case ESCO_CODING_FORMAT_ULAW:
                case ESCO_CODING_FORMAT_ALAW:
                case ESCO_CODING_FORMAT_CVSD:
                    if (sco_cb.esco_para.input_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
                        sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_LINEAR;
                    else
                        sco_cb.codec_para.input_format = sco_cb.esco_para.receive_coding_format.coding_format;
                    sco_cb.codec_para.input_rate   = 8000;
                    break;
                case ESCO_CODING_FORMAT_MSBC: // stack bugs
                    sco_cb.esco_para.receive_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
                case ESCO_CODING_FORMAT_TRANSPNT:
                    sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_MSBC;
                    sco_cb.codec_para.input_rate   = 16000;
                    break;
                default:
                    ALOGD("Unsupport receive coding format");
                    break;
            }

            sco_cb.esco_para.input_data_path  = ESCO_DATA_PATH_HCI; // input data path, set to VOHCI
            sco_cb.esco_para.output_data_path = ESCO_DATA_PATH_HCI; // output data path, set to VOHCI
            memcpy(&recv_buffer[9], &sco_cb.esco_para, sizeof(sco_cb.esco_para));
            break;
#endif

        case HCI_SET_EVENT_MASK:
            AICBTDBG(LOGINFO, "%s HCI_SET_EVENT_MASK", __func__);
            memcpy(&set_event_mask[1],recv_buffer,total_length);
            set_event_mask[0] = 1;
//            Heartbeat_init();
            break;

        case HCI_ACCEPT_CONNECTION_REQUEST:
            property_get("persist.vendor.bluetooth.prefferedrole", prop_value, "none");
            if (strcmp(prop_value, "none") != 0) {
                int role = recv_buffer[9];
                if (role == 0x01 && (strcmp(prop_value, "master") == 0))
                    recv_buffer[9] = 0x00;
                else if (role == 0x00 && (strcmp(prop_value, "slave") == 0))
                    recv_buffer[9] = 0x01;
            }
            break;

        case HCI_BLE_WRITE_ADV_PARAMS:
            if (aicbt_version.hci_version> HCI_PROTO_VERSION_4_2) {
                break;
            }
            aicbt_adv_con.adverting_type = recv_buffer[7];
            property_get("persist.vendor.aicbtadvdisable", prop_value, "false");
            if (aicbt_adv_con.adverting_type == 0x00 && (strcmp(prop_value, "true") == 0)) {
                recv_buffer[7] = 0x03;
                aicbt_adv_con.adverting_type = 0x03;
            }
            break;

        case HCI_BLE_WRITE_ADV_ENABLE:
            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
                break;
            }
            if (recv_buffer[3] == 0x01) {
                aicbt_adv_con.adverting_start = TRUE;
            } else if (recv_buffer[3] == 0x00) {
                aicbt_adv_con.adverting_type = 0;
                aicbt_adv_con.adverting_enable = FALSE;
                aicbt_adv_con.adverting_start = FALSE;
            }
            break;

        case HCI_BLE_CREATE_LL_CONN:
            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
                break;
            }
            if (aicbt_adv_con.adverting_enable &&
                ((aicbt_adv_con.adverting_type == 0x00) ||
                (aicbt_adv_con.adverting_type == 0x01) ||
                (aicbt_adv_con.adverting_type == 0x04))) {
                uint8_t disable_adv_cmd[5] = {0x01, 0x0A, 0x20, 0x01, 0x00};
                aicbt_adv_con.adverting_enable = FALSE;
                userial_send_cmd_to_controller(disable_adv_cmd, 5);
            }
            break;

        case HCI_BLE_ADV_FILTER_OCF:
            {
                uint8_t opcode = recv_buffer[3];
                if (opcode == 0x2) {     // BTM_BLE_META_PF_ADDR
                    uint8_t action = recv_buffer[4];
                    if (action == 0x0) { // ADD, BTM_BLE_META_PF_ENABLE
                        adv_tracking.evt[4] = recv_buffer[5];             // filter index
                        memcpy(&adv_tracking.evt[7], &recv_buffer[6], 6); // device address
                        adv_tracking.state = ADV_TRACKING_SET;
                    }
                }
            }
            break;
        case HCI_INQUIRY:
            {
                if(aic_ble_only){
                    uint8_t inquiry_cmd_status[]={0x04,0x0f,0x04,0x00,0x01,0x01,0x04};
                    uint8_t inquiry_complete[]={0x04,0x01,0x01,0x00};
                    userial_recv_uart_rawdata(inquiry_cmd_status, sizeof(inquiry_cmd_status));
                    userial_recv_uart_rawdata(inquiry_complete, sizeof(inquiry_complete));
                    return false;
                }
            }
            break;
        case HCI_WRITE_LOOPBACK_MODE:
            AICBTDBG(LOGINFO, "%s HCI_WRITE_LOOPBACK_MODE\r\n", __func__);
            break;
        case HCI_INQUIRY_CANCEL:
            {
                if(aic_ble_only){
                    uint8_t inquiry_cancel_cmd_cmp[]={0x04,0x0e,0x04,0x05,0x02,0x04,0x00};
                    userial_recv_uart_rawdata(inquiry_cancel_cmd_cmp, sizeof(inquiry_cancel_cmd_cmp));
                    return false;
                }
            }
            break;
        case HCI_CHANGE_LOCAL_NAME:
            {
                memcpy(&chgloclname[1],recv_buffer,total_length);
                chgloclname[0] = 1;
            }
            break;
        case HCI_WRITE_EXT_INQ_RESPONSE:
            {
                memcpy(&eir[1],recv_buffer,total_length);
                eir[0] = 1;
            }
            break;
        case HCI_WRITE_CLASS_OF_DEVICE:
            {
                memcpy(&cod[1],recv_buffer,total_length);
                cod[0] = 1;
            }
            break;
        case HCI_WRITE_SIMPLE_PAIRING_MODE:
            {
                memcpy(&simple_pair_mode[1],recv_buffer,total_length);
                simple_pair_mode[0] = 1;
            }
            break;
        case HCI_WRITE_LE_HOST_SUPPORT:
            {
                memcpy(&le_host_support[1],recv_buffer,total_length);
                le_host_support[0] = 1;
            }
            break;
        case HCI_WRITE_SECURE_CONNS_SUPPORT:
            {
                memcpy(&secure_conn_host_support[1],recv_buffer,total_length);
                secure_conn_host_support[0] = 1;
            }
            break;
        case HCI_BLE_SET_EVENT_MASK:
            {
                memcpy(&le_set_event_mask[1],recv_buffer,total_length);
                le_set_event_mask[0] = 1;
            }
            break;
        case HCI_BLE_WRITE_RANDOM_ADDR:
            {
                memcpy(&set_le_random_addr[1],recv_buffer,total_length);
                set_le_random_addr[0] = 1;
            }
            break;
		case HCI_BLE_ADD_WHITE_LIST:
			{
				if(!aic_check_store_white_list(&recv_buffer[4])){
					aic_store_white_list(recv_buffer,total_length);
				}				
			}
			break;
		case HCI_BLE_CLEAR_WHITE_LIST:
			{
				aic_clean_all_store_white_list();
			}
			break;
		case HCI_BLE_REMOVE_WHITE_LIST:
			{
				if(aic_check_store_white_list(&recv_buffer[4])){
					aic_clean_store_white_list(&recv_buffer[4]);
				}	
			}
			break;
        default:
            break;
    }
    return true;
}
#endif


//This recv data from bt process. The data type only have ACL/SCO/COMMAND
// direction  BT HOST ----> CONTROLLER
static void userial_recv_H4_rawdata(void *context)
{
    AIC_UNUSED(context);
    serial_data_type_t type = 0;
    ssize_t bytes_read;
    uint16_t opcode;
    uint16_t transmitted_length = 0;
    //unsigned char *buffer = NULL;
    bool not_ignore_cmd = false;

    switch (packet_recv_state) {
        case AICBT_PACKET_IDLE:
            packet_bytes_need = 1;
            do {
                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &type, 1));
                if (bytes_read == -1) {
                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
                    return;
                }
                if (!bytes_read && packet_bytes_need) {
                    ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
                    return;
                }

                if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
                    ALOGE("%s invalid data type: %d", __func__, type);
                    assert((type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO));
                } else {
                    packet_bytes_need -= bytes_read;
                    packet_recv_state = AICBT_PACKET_TYPE;
                    current_type = type;
                    h4_read_buffer[0] = type;
                }
            } while(packet_bytes_need);
            // fall through

        case AICBT_PACKET_TYPE:
            packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(current_type)];
            h4_read_length = 0;
            packet_recv_state = AICBT_PACKET_HEADER;
            // fall through

        case AICBT_PACKET_HEADER:
            do {
                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &h4_read_buffer[h4_read_length + 1], packet_bytes_need));
                if (bytes_read == -1) {
                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
                    return;
                }
                if (!bytes_read && packet_bytes_need) {
                    ALOGE("%s, state = %d, bytes_read 0, type : %d", __func__, packet_recv_state, current_type);
                    return;
                }
                packet_bytes_need -= bytes_read;
                h4_read_length += bytes_read;
            }while(packet_bytes_need);
            packet_recv_state = AICBT_PACKET_CONTENT;

            if (current_type == DATA_TYPE_ACL) {
                packet_bytes_need = *(uint16_t *)&h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
            } else if (current_type == DATA_TYPE_EVENT) {
                packet_bytes_need = h4_read_buffer[EVENT_DATA_LENGTH_INDEX];
            } else {
                packet_bytes_need = h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
            }
            // fall through

        case AICBT_PACKET_CONTENT:
            while(packet_bytes_need) {
                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &h4_read_buffer[h4_read_length + 1], packet_bytes_need));
                if (bytes_read == -1) {
                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
                    return;
                }
                if (!bytes_read) {
                    ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
                    return;
                }

                packet_bytes_need -= bytes_read;
                h4_read_length += bytes_read;
            }
            packet_recv_state = AICBT_PACKET_END;
            // fall through

        case AICBT_PACKET_END:
            switch (current_type) {
                case DATA_TYPE_COMMAND:
#ifdef AIC_HANDLE_CMD
			not_ignore_cmd = userial_handle_cmd(&h4_read_buffer[1], h4_read_length);
#endif
			if(not_ignore_cmd){
                AICBTDBG(LOGDEBUG, "%s not ignore cmd \r\n", __func__);
			}else{
                AICBTDBG(LOGDEBUG, "%s ignore cmd \r\n", __func__);
                break;
            }
            
			if (aicbt_transtype & AICBT_TRANS_H4) {
				h4_int_transmit_data(h4_read_buffer, (h4_read_length + 1));
			} else {
				opcode = *(uint16_t *)&h4_read_buffer[1];
				if (opcode == HCI_VSC_H5_INIT) {
					h5_int_interface->h5_send_sync_cmd(opcode, NULL, h4_read_length);
				} else {
					transmitted_length = h5_int_interface->h5_send_cmd(type, &h4_read_buffer[1], h4_read_length);
				}
			}
			break;

                case DATA_TYPE_ACL:
                    userial_send_acl_to_controller(h4_read_buffer, (h4_read_length + 1));
                    break;

                case DATA_TYPE_SCO:
#ifdef CONFIG_SCO_OVER_HCI
                    if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_MSBC) {
                        ALOGE("sco len %d,%x,%x,%x,%x", h4_read_length,h4_read_buffer[0],h4_read_buffer[1],h4_read_buffer[2],h4_read_buffer[3]);
                        AIC_BUFFER* skb_msbc_enc_data;
                        skb_msbc_enc_data = RtbAllocate(244, 0);
                        memcpy(skb_msbc_enc_data->Data, h4_read_buffer, 244);
                        RtbAddTail(skb_msbc_enc_data, 244);
                        pthread_mutex_lock(&sco_cb.msbc_send_mutex);
                        RtbQueueTail(sco_cb.send_msbc_enc_data, skb_msbc_enc_data);
                        pthread_cond_signal(&sco_cb.msbc_send_cond);
                        pthread_mutex_unlock(&sco_cb.msbc_send_mutex);
                    } else {
#endif
                        userial_send_sco_to_controller(h4_read_buffer, (h4_read_length + 1));
                        
#ifdef CONFIG_SCO_OVER_HCI
                    }
#endif
                    break;

                default:
                    ALOGE("%s invalid data type: %d", __func__, current_type);
                    break;
            }
            
            aic_btsnoop_capture(&h4_read_buffer[0], false);
            break;
            
        default:
            break;
    }

    packet_recv_state = AICBT_PACKET_IDLE;
    packet_bytes_need = 0;
    current_type = 0;
    h4_read_length = 0;
}

static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, uint16_t length) {
    assert(data != NULL);
    assert(length > 0);

    if (type != DATA_TYPE_H5) {
        ALOGE("%s invalid data type: %d", __func__, type);
        return 0;
    }

    uint16_t transmitted_length = 0;
    while (length > 0 && vnd_userial.btdriver_state) {
        ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
        switch (ret) {
            case -1:
                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                goto done;

            case 0:
                // If we wrote nothing, don't loop more because we
                // can't go to infinity or beyond, ohterwise H5 can resend data
                ALOGE("%s, ret %zd", __func__, ret);
                goto done;

            default:
                transmitted_length += ret;
                length -= ret;
                break;
        }
    }

done:
    return transmitted_length;

}

#ifdef AIC_HANDLE_EVENT
extern void ms_delay (uint32_t timeout);
static bool userial_handle_event(unsigned char * recv_buffer, int total_length)
{
    AIC_UNUSED(total_length);
    uint8_t event;
    uint8_t *p_data = recv_buffer;
    event = p_data[0];
    bool handle_ret = false;
    uint8_t status;
    uint16_t handle;
    switch (event) {
    case HCI_COMMAND_COMPLETE_EVT:
    {
        uint16_t opcode = *((uint16_t*)&p_data[3]);
        uint8_t *stream = &p_data[6];
        if (opcode == HCI_READ_LOCAL_VERSION_INFO) {
            STREAM_TO_UINT8(aicbt_version.hci_version, stream);
            STREAM_TO_UINT16(aicbt_version.hci_revision, stream);
            STREAM_TO_UINT8(aicbt_version.lmp_version, stream);
            STREAM_TO_UINT16(aicbt_version.manufacturer, stream);
            STREAM_TO_UINT16(aicbt_version.lmp_subversion, stream);
        } else if (opcode == HCI_BLE_WRITE_ADV_ENABLE){
            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
                break;
            }
            if (aicbt_adv_con.adverting_start &&(p_data[5] == HCI_SUCCESS)) {
                aicbt_adv_con.adverting_enable = TRUE;
                aicbt_adv_con.adverting_start = FALSE;
            }
        } else if (opcode == HCI_RESET) {
            if (close_state == 0) {
                ALOGD("hci reset event received before serial close");
                close_state = 1;
            }
        } else if (opcode == HCI_BLE_ADV_FILTER_OCF) {
            uint8_t status = p_data[5];       // Success (0x00)
            uint8_t apcf_opcode = p_data[6];  // APCF Opcode: APCF Set Filtering parameters (0x01)
            uint8_t action = p_data[7];       // Action: Add (0x00)
            if (status == 0x00 && apcf_opcode == 0x01 && action == 0x00 && adv_tracking.state == ADV_TRACKING_SET) {
                adv_tracking.state = ADV_TRACKING_ON;
            }
        }
    }
    break;

    case HCI_LE_META_EVT: {
        uint8_t opcode = *((uint8_t*)&p_data[2]);
        uint16_t remain_length = sizeof(adv_tracking.evt);
        uint16_t transmitted_length = 0;
		if(1)
        {
            uint8_t len = p_data[1];
            uint8_t subevent = p_data[2];
            if(subevent == HCI_BLE_CONN_COMPLETE_EVT){
                uint8_t status = p_data[3];
                uint16_t handle;
                uint8_t *ptr = &p_data[4];
                handle = ((uint16_t)(*(ptr)) | (((uint16_t)(*((ptr) + 1))) << 8));
                if(status == 0){
                    aic_store_acl_handle(handle);
                }
            }else if(subevent == HCI_BLE_ENHANCED_CONN_COMPLETE_EVT){
                uint8_t status = p_data[3];
                uint16_t handle;
                uint8_t *ptr = &p_data[4];
                handle = ((uint16_t)(*(ptr)) | (((uint16_t)(*((ptr) + 1))) << 8));
                if(status == 0){
                    aic_store_acl_handle(handle);
                }
            }
        }
        if (opcode == HCI_BLE_ADV_PKT_RPT_EVT && adv_tracking.state == ADV_TRACKING_ON) {
            for (int i = 0; i < 6; i++) {
                if (p_data[11 - i] != adv_tracking.evt[12 - i]) {
                    return 0;
                }
            }
            adv_tracking.state = ADV_FILTERED;
        }

        // Trigger a new BLE_TRACKING event to stack
        if (adv_tracking.state == ADV_FILTERED) {
            adv_tracking.evt[5] = 0;
            ALOGD("adv_tracking_report, device found, %02x:%02x:%02x:%02x:%02x:%02x",
                    adv_tracking.evt[12], adv_tracking.evt[11], adv_tracking.evt[10],
                    adv_tracking.evt[ 9], adv_tracking.evt[ 8], adv_tracking.evt[ 7]);
            while (remain_length > 0) {
                ssize_t ret;
                AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], adv_tracking.evt + transmitted_length, remain_length));
                if (ret > 0) {
                    transmitted_length += ret;
                    remain_length -= ret;
                } else {
                    if (ret == -1)
                        ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                }
            }
            adv_tracking.timestamp = get_timestamp();
            adv_tracking.state = ADV_TRACKING_OFF;
        } else if (adv_tracking.state == ADV_TRACKING_OFF && (get_timestamp() - adv_tracking.timestamp) >= 30000000) {
            adv_tracking.evt[5] = 1;
            ALOGD("adv_tracking_report, device lost, %02x:%02x:%02x:%02x:%02x:%02x",
                    adv_tracking.evt[12], adv_tracking.evt[11], adv_tracking.evt[10],
                    adv_tracking.evt[ 9], adv_tracking.evt[ 8], adv_tracking.evt[ 7]);
            while (remain_length > 0) {
                ssize_t ret;
                AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], adv_tracking.evt + transmitted_length, remain_length));
                if (ret > 0) {
                    transmitted_length += ret;
                    remain_length -= ret;
                } else {
                    if (ret == -1)
                        ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                }
            }
            adv_tracking.state = ADV_TRACKING_IDLE;
        }
    }
    break;

    case HCI_CONNECTION_COMP_EVT:
    {
        ALOGE("%s: HCI_EV_SYNC_CONN_COMPLETE(0x%02x)", __func__, *p_data);
        status = *(p_data + 2);
        handle = *(p_data + 3) | *(p_data + 4) << 8;
        if(status == 0){
            aic_store_acl_handle(handle);
        }
    }
    break;

#ifdef CONFIG_SCO_OVER_HCI
    case HCI_ESCO_CONNECTION_COMP_EVT: {
        ALOGD("%s, HCI_ESCO_CONNECTION_COMP_EVT", __func__);
        if (p_data[2] != 0) {
            sco_cb.thread_sco_running = false;
            sco_cb.thread_recv_sco_running = false;
            sco_cb.thread_send_sco_running = false;
        } else {
            sco_cb.sco_handle = *((uint16_t *)&p_data[3]);
            pthread_attr_t thread_attr;
            pthread_attr_init(&thread_attr);
            pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
            sco_cb.thread_sco_running = true;
            sco_cb.thread_recv_sco_running = false;
            sco_cb.thread_send_sco_running = false;

            RtbEmptyQueue(sco_cb.recv_sco_data);
            switch (sco_cb.codec_para.input_format) {
                case ESCO_CODING_FORMAT_LINEAR:
                    sco_cb.sco_packet_len = 120;    // Get from esco data package, how decide it dynamic?
                    break;
                case ESCO_CODING_FORMAT_CVSD:
                    sco_cb.sco_packet_len = 240;    // every 5 cvsd packets form a sco pcm data
                    break;
                case ESCO_CODING_FORMAT_MSBC:
                    sco_cb.sco_packet_len = 60;
                    break;
                default:
                    ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
                    break;
            }
            sco_cb.current_pos = 0;
        }
        memset(&sco_cb.sbc_enc, 0, sizeof(sbc_t));
        sbc_init_msbc(&sco_cb.sbc_enc, 0L);
        sco_cb.sbc_enc.endian = SBC_LE;
        memset(&sco_cb.sbc_dec, 0, sizeof(sbc_t));
        sbc_init_msbc(&sco_cb.sbc_dec, 0L);
        sco_cb.sbc_dec.endian = SBC_LE;

        ALOGD("userial_handle_event sco_handle: %d", sco_cb.sco_handle);
        if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_MSBC) {
            userial_sco_ctrl_skt_handle(SCO_CTRL_CMD_OUT_START);
        }
        userial_sco_ctrl_skt_handle(SCO_CTRL_CMD_IN_START);
#if AIC_SCO_UART_SUPPORT
      if(p_data[2] == 0) {
        pthread_attr_t thread_attr;
        pthread_attr_init(&thread_attr);
        pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
        btif_aic_sco_cb.air_mode = p_data[18];
        ALOGD("%s: air_mode= %d", __func__,btif_aic_sco_cb.air_mode);
        btif_aic_sco_cb.worker_thread_running = true;
        if (pthread_create(&btif_aic_sco_cb.worker_thread, &thread_attr, worker_thread, NULL)!= 0) {
          ALOGD("%s: unable to start up aic sco thread", __func__);
        } else {
          RtbEmptyQueue(btif_aic_sco_cb.snd_recv_msg_queue);
          RtbEmptyQueue(btif_aic_sco_cb.data_msg_queue);
        }
      }
#endif
    }
    break;

    case HCI_DISCONNECTION_COMP_EVT: {
        ALOGD("%s, HCI_DISCONNECTION_COMP_EVT recv handle %x, sco_handle %x", __func__,(*((uint16_t *)&p_data[3])),sco_cb.sco_handle);
        status = *(p_data + 2);
        handle = *(p_data + 3) | *(p_data + 4) << 8;
        if(aic_check_store_handle(handle)){
            aic_clean_store_acl_handle(handle);
        }
        if ((*((uint16_t *)&p_data[3])) == sco_cb.sco_handle) {
            sco_cb.sco_handle = 0;
            RtbEmptyQueue(sco_cb.recv_sco_data);
            if (sco_cb.thread_sco_running) {
                sco_cb.thread_sco_running = false;
                //unsigned char close_signal = 1;
                //ssize_t ret;
                //AIC_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
                userial_sco_ctrl_skt_handle(SCO_CTRL_CMD_CLOSE);
            }
            sbc_finish(&sco_cb.sbc_enc);
            sbc_finish(&sco_cb.sbc_dec);
#if AIC_SCO_UART_SUPPORT
          // Exit the thread
          if (btif_aic_sco_cb.worker_thread_running) {
            btif_aic_sco_cb.worker_thread_running = false;
            RtbEmptyQueue(btif_aic_sco_cb.snd_recv_msg_queue);
            RtbEmptyQueue(btif_aic_sco_cb.data_msg_queue);
          }
#endif
        }
    }
    break;
#else
    case HCI_DISCONNECTION_COMP_EVT:
    {
        ALOGE("%s: HCI_EV_DISCONN_COMPLETE(0x%02x)", __func__, *p_data);
        status = *(p_data + 2);
        handle = *(p_data + 3) | *(p_data + 4) << 8;
        if(aic_check_store_handle(handle)){
            aic_clean_store_acl_handle(handle);
        }
    }
    break;
#endif
    case HCI_HARDWARE_ERROR_EVT:
    {
        uint8_t reason = p_data[2];
        ALOGE("hw_error,reason = 0x%x\n",reason);
        if(USERIAL_HWERR_CODE_USB_RESUME == reason){
            handle_ret = true;
            if(le_set_event_mask[0] == 1){
                h4_int_transmit_data(le_set_event_mask, 12);
                ms_delay(2);
            }
            if(set_event_mask[0] == 1){
                h4_int_transmit_data(set_event_mask, 12);
                ms_delay(2);
            }
            if(chgloclname[0] == 1){
                h4_int_transmit_data(chgloclname, 252);
                ms_delay(2);
            }
            if(eir[0] == 1){
                h4_int_transmit_data(eir, 245);
                ms_delay(2);
            }
            if(cod[0] == 1){
                h4_int_transmit_data(cod, 7);
                ms_delay(2);
            }
            if(simple_pair_mode[0] == 1){
                h4_int_transmit_data(simple_pair_mode, 5);
                ms_delay(2);
            }
            if(le_host_support[0] == 1){
                h4_int_transmit_data(le_host_support, 6);
                ms_delay(2);
            }
            if(secure_conn_host_support[0] == 1){
                h4_int_transmit_data(secure_conn_host_support, 5);
                ms_delay(2);
            }
            if(set_le_random_addr[0] == 1){
                h4_int_transmit_data(set_le_random_addr, 10);
                ms_delay(2);
            }
			aic_resume_all_store_white_list();
            aic_disconnect_all_store_acl_handle();
        }else{
            //do real hardware error.
        }
    }
    break;
#if 0
    case HCI_BLE_EVENT:
    {
        uint8_t len = p_data[1];
        uint8_t subevent = p_data[2];
        if(subevent == HCI_BLE_CONN_COMPLETE_EVT){
            uint8_t status = p_data[3];
            uint16_t handle;
            uint8_t *ptr = &p_data[4];
            handle = ((uint16_t)(*(ptr)) | (((uint16_t)(*((ptr) + 1))) << 8));
            if(aic_check_store_handle(handle)){
                aic_clean_store_acl_handle(handle);
            }
        }else if(subevent == HCI_BLE_ENHANCED_CONN_COMPLETE_EVT){
            uint8_t status = p_data[3];
            uint16_t handle;
            uint8_t *ptr = &p_data[4];
            handle = ((uint16_t)(*(ptr)) | (((uint16_t)(*((ptr) + 1))) << 8));
            if(aic_check_store_handle(handle)){
                aic_clean_store_acl_handle(handle);
            }
        }
    }
    break;
#endif
	
    default :
    break;
  }
return handle_ret;
}

#ifdef CONFIG_SCO_OVER_HCI
static void userial_enqueue_recv_sco_data(unsigned char *recv_buffer, int total_length)
{
    AIC_UNUSED(total_length);
    uint8_t sco_length;
    uint8_t *p_data = recv_buffer;
    AIC_BUFFER *skb_sco_data;
    int i;
    uint16_t sco_handle = (*((uint16_t *)p_data)) & 0x0FFF;
    uint8_t  packet_flag = (uint8_t)((sco_handle >> 12) & 0x0003);
    uint16_t current_pos = sco_cb.current_pos;
    uint16_t sco_packet_len = sco_cb.sco_packet_len;

    if (sco_handle == sco_cb.sco_handle) {
        sco_length = p_data[SCO_PREAMBLE_SIZE - 1];
        p_data += SCO_PREAMBLE_SIZE;

        switch (sco_cb.codec_para.input_format) {
            case ESCO_CODING_FORMAT_LINEAR:  // PCM raw data
                skb_sco_data = RtbAllocate(sco_length, 0);
                memcpy(skb_sco_data->Data, p_data, sco_length);
                RtbAddTail(skb_sco_data, sco_length);
                pthread_mutex_lock(&sco_cb.sco_recv_mutex);
                RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
                pthread_cond_signal(&sco_cb.sco_recv_cond);
                pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
                return;
            case ESCO_CODING_FORMAT_CVSD:    // CVSD codec
            case ESCO_CODING_FORMAT_MSBC:    // MSBC codec
                if (packet_flag != 0x00)
                    ALOGE("sco data receive wrong packet_flag : %d", packet_flag);
                if (current_pos) {
                    if ((sco_packet_len - current_pos) <= sco_length) {
                        memcpy(&sco_cb.enc_data[current_pos], p_data, (sco_packet_len - current_pos));
                        skb_sco_data = RtbAllocate(sco_packet_len, 0);
                        memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
                        RtbAddTail(skb_sco_data, sco_packet_len);
                        pthread_mutex_lock(&sco_cb.sco_recv_mutex);
                        RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
                        pthread_cond_signal(&sco_cb.sco_recv_cond);
                        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
                        sco_cb.current_pos = 0;
                        p_data += (sco_packet_len - current_pos);
                        sco_length -= (sco_packet_len - current_pos);
                    } else {
                        memcpy(&sco_cb.enc_data[current_pos], p_data, sco_length);
                        sco_cb.current_pos += sco_length;
                        return;
                    }
                }
                break;
            default:
                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
                return;
        }

        switch (sco_cb.codec_para.input_format) {
            case ESCO_CODING_FORMAT_CVSD:    // Cvsd codec
                for (i = 0; i < (sco_length/sco_packet_len); i++) {
                    skb_sco_data = RtbAllocate(sco_packet_len, 0);
                    memcpy(skb_sco_data->Data, p_data + i*sco_packet_len, sco_packet_len);
                    RtbAddTail(skb_sco_data, sco_packet_len);
                    RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
                }
                if ((sco_length/sco_packet_len)) {
                    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
                    pthread_cond_signal(&sco_cb.sco_recv_cond);
                    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
                }
                i = (sco_length % sco_packet_len);
                current_pos = sco_length - i;
                if (i) {
                    memcpy(sco_cb.enc_data, p_data + current_pos, i);
                    sco_cb.current_pos = i;
                }
                break;
            case ESCO_CODING_FORMAT_MSBC:
                for (i = 0; i < sco_length; i++) {
                    if ((p_data[i] == 0x01) && ((p_data[i+1] & 0x0f) == 0x08) && (p_data[i+2] == 0xAD)) {
                        if ((sco_length - i) < sco_packet_len) {
                            memcpy(sco_cb.enc_data, &p_data[i], (sco_length - i));
                            sco_cb.current_pos = sco_length - i;
                            return;
                        } else {
                            memcpy(sco_cb.enc_data, &p_data[i], sco_packet_len);   //complete msbc data
                            skb_sco_data = RtbAllocate(sco_packet_len, 0);
                            memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
                            RtbAddTail(skb_sco_data, sco_packet_len);
                            pthread_mutex_lock(&sco_cb.sco_recv_mutex);
                            RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
                            pthread_cond_signal(&sco_cb.sco_recv_cond);
                            pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
                            sco_cb.current_pos = 0;
                            i += (sco_packet_len - 1);
                        }
                    }
                }
                break;
            default:
                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
                break;
            }
    }
}
#endif

//fw log save to file start
FILE *fw_log_file_p = NULL;
int current_lines = 0;
#define MAX_LINES 10000
#define LINE_LENGTH 256

#define LOG_FILE_PATH "/data/misc/bluedroid/"
#define TEMP_LOG_FILE LOG_FILE_PATH".temp_log.txt"
#define LOG_FILE LOG_FILE_PATH"bt_ic_log.txt"
//int log_inedx = 0;

int count_lines(FILE *fp) {
    rewind(fp);
    int count = 0;
    char buffer[LINE_LENGTH];
    
    while (fgets(buffer, sizeof(buffer), fp)) {
        if (buffer[strlen(buffer)-1] == '\n')
            count++;
    }
    return count;
}

void rotate_log(FILE **fp) {
    FILE *temp = fopen(TEMP_LOG_FILE, "a+");
    char buffer[LINE_LENGTH];
    
    rewind(*fp);
    fgets(buffer, sizeof(buffer), *fp);
    
    while (fgets(buffer, sizeof(buffer), *fp)) {
        fputs(buffer, temp);
    }
    
    fclose(*fp);
    fclose(temp);
    remove(LOG_FILE);
    rename(TEMP_LOG_FILE, LOG_FILE);
    
    *fp = fopen(LOG_FILE, "a+");
    current_lines = MAX_LINES;
}

uint64_t aic_btsnoop_timestamp(void);
extern const uint64_t BTSNOOP_EPOCH_DELTA;

void write_to_file(char* log){
    uint64_t timestamp = 0;
    time_t current_time = time(NULL);
    struct tm *time_created = localtime(&current_time);
    char config_time_created[sizeof("YYYY-MM-DD-HH:MM:SS")];
    uint32_t usec;
    char buff[255];

    memset(buff, 0, 255);
    strftime(config_time_created, sizeof("YYYY-MM-DD-HH:MM:SS"), "%Y-%m-%d-%H:%M:%S", time_created);
    timestamp = aic_btsnoop_timestamp() - BTSNOOP_EPOCH_DELTA;
    usec = (uint32_t)(timestamp % 1000000LL);
    sprintf(buff, "%s:%d\t %s", config_time_created, usec, log);
    
    fputs(buff, fw_log_file_p);
    current_lines++;

    if (current_lines >= MAX_LINES + 1) {
        rotate_log(&fw_log_file_p);
    }
    fflush(fw_log_file_p);

}

void write_fw_to_file(char* log, int len){
    char buff[255];
    char sub_buff[255];
    int index = 0;
    int sub_index = 0;

    if (!fw_log_file_p) {
        return;
    }
    memset(buff, 0, 255);
    memset(sub_buff, 0, 255);
    memcpy(buff, log, len);
    index = 0;
    sub_index = 0;
    
    do{
        sub_buff[sub_index] = buff[index];
        sub_index++;
        if(sub_buff[sub_index - 1] == 0x0a){//\n
            write_to_file((char*)(&sub_buff[0]));
            memset(sub_buff, 0, sub_index);
            sub_index = 0;
        }
        index++;
        len--;
    }while(buff[index] != 0x00 && len != 0);
    
}

void init_fw_log(void){
    fw_log_file_p = fopen(LOG_FILE, "a+");
    
    if (!fw_log_file_p) {
        AICBTDBG(LOGERROR, "File open failed");
        return;
    }

    current_lines = count_lines(fw_log_file_p);

    AICBTDBG(LOGINFO, "Log file:%s ready (current lines: %d)\r\n", LOG_FILE, current_lines);

}

void deinit_fw_log(void){
    if(fw_log_file_p){
        fclose(fw_log_file_p);
        AICBTDBG(LOGINFO, "Log file close\r\n");
    }
}
//fw logsave to file end

int extend_feature_page = 0;
//static char local_extended_features_page0[10] = {0x00, 0x02, 0xbf, 0xee, 0xcd, 0xfa, 0xd8, 0x3d, 0x7b, 0x87}; // ble, bredr, ssp
//static char local_extended_features_page1[10] = {0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static char local_extended_features_page0[10] = {0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00};
static char local_extended_features_page1[10] = {0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static char local_extended_features_page2[10] = {0x02, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
#if 0
static char local_supported_commands[64] = {
    0x20, 0x00, 0x80, 0x00, 0x00, 0xc0, 0x00, 0x00,
    0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x28, 0x22,
    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00,
    0x00, 0xf7, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
    0x30, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
#if 0
static char local_supported_commands[64] = {
	0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x28, 0x22, 0x00, 0x00, 0x00, 0x00,
	0x10, 0x00, 0x00, 0x00, 0x10, 0xf7, 0xff, 0xff, 0x0f, 0x00,
	0x00, 0x00, 0x00, 0x30, 0x00, 0x08, 0x00, 0x00, 0x80, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00
};
#endif

static char local_supported_commands[64] = {
    0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x28, 0x22, 0x00, 0x00, 0x00, 0x00,
    0x10, 0x00, 0x00, 0x00, 0x10, 0xf7, 0xff, 0xff, 0x0f, 0x00,
    0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00
};

static char local_version_info[15] = {
	0x04, 0x0e, 0x0c, 0x01, 0x01, 0x10, 0x00, 0x0b, 0x14, 0x00, 
	0x0b, 0x3b, 0x0b, 0x14, 0x00
};
static char buffer_size[7] = {0xfd, 0x03, 0xff, 0x08, 0x00, 0x04, 0x00};
static char local_name[248] = {'a', 'i', 'c', '-', 'b', 'l', 'e'};

void aic_event_handle(unsigned char * recv_buffer){
	unsigned char * p_data = recv_buffer;
	uint16_t opcode;
	if(p_data[0] == DATA_TYPE_EVENT && p_data[1] == HCI_COMMAND_COMPLETE_EVT){
		opcode = *((uint16_t*)&p_data[4]);
		AICBTDBG(LOGDEBUG, "%s, aic_ble_only opcode:%04x \r\n", __func__, opcode);
		
		switch(opcode){
			case HCI_READ_LOCAL_VERSION_INFO:
				if(aic_ble_only){
					memcpy(&p_data[0], local_version_info, 15);
				}
				break;
			case HCI_READ_LOCAL_SUPPORTED_CMDS:
				if(aic_ble_only){
					memcpy(&p_data[7], local_supported_commands, 64);
				}
				break;
			case HCI_READ_LOCAL_FEATURES:
				if(p_data[11] & (1 << 5)){
					//ALOGD("%s, aic_ble_only feature:%04x \r\n", __func__, p_data[11]);
					AICBTDBG(LOGINFO, "%s, aic_ble_only enable!! \r\n", __func__);
					aic_ble_only = true;
					extend_feature_page = 0;
				}
				break;
			case HCI_READ_LOCAL_EXT_FEATURES:
				if(aic_ble_only){
					p_data[6] = 0x00;//status:success
					if(extend_feature_page == 0){//page 0
						memcpy(&p_data[7], local_extended_features_page0, 10);
						extend_feature_page = 1;
					}else if(extend_feature_page == 1){//page 1
						memcpy(&p_data[7], local_extended_features_page1, 10);
						extend_feature_page = 2;
					}else if (extend_feature_page == 2){//page 2
						memcpy(&p_data[7], local_extended_features_page2, 10);
						extend_feature_page = 0;
					}
				}
				break;
			case HCI_READ_BUFFER_SIZE:
				if(aic_ble_only){
					p_data[6] = 0x00;//status:success
					memcpy(&p_data[7], buffer_size, 7);
				}
				break;
			case HCI_WRITE_LE_HOST_SUPPORT:
				if(aic_ble_only){
					p_data[6] = 0x00;//status:success
				}
				break;
			case HCI_READ_LOCAL_NAME:
				if(aic_ble_only){
					p_data[6] = 0x00;//status:success
					memcpy(&p_data[7], local_name, 248);
				}
				break;
			case HCI_WRITE_SIMPLE_PAIRING_MODE:
				if(aic_ble_only){
					p_data[6] = 0x00;//status:success
				}
				break;
			case HCI_WRITE_SECURE_CONNS_SUPPORT:
				if(aic_ble_only){
					p_data[6] = 0x00;//status:success
				}
				break;
			case HCI_WRITE_DEF_POLICY_SETTINGS:
				if(aic_ble_only){
					p_data[6] = 0x01;//status:unknown
				}
				break;
			case HCI_WRITE_CLASS_OF_DEVICE:
				if(aic_ble_only){
					p_data[6] = 0x01;//status:unknown
				}
				break;
			case HCI_WRITE_PAGE_TOUT:
				if(aic_ble_only){
					p_data[6] = 0x01;//status:unknown
				}
				break;
			case HCI_CHANGE_LOCAL_NAME:
				if(aic_ble_only){
					p_data[6] = 0x01;//status:unknown
				}
				break;
			case HCI_WRITE_INQUIRYSCAN_CFG:
				if(aic_ble_only){
					p_data[6] = 0x01;//status:unknown
				}
				break;
			case HCI_WRITE_SCAN_ENABLE:
				if(aic_ble_only){
					p_data[6] = 0x01;//status:unknown
				}
				break;
			case HCI_WRITE_PAGESCAN_CFG:
				if(aic_ble_only){
					p_data[6] = 0x01;//status:unknown
				}
				break;
			case HCI_INQUIRY_CANCEL:
				if(aic_ble_only){
					p_data[6] = 0x00;//status:success
				}
				break;
			case HCI_DELETE_STORED_LINK_KEY:
				if(aic_ble_only){
					p_data[6] = 0x12;//status:invalid
				}
				break;
            case HCI_SET_EVENT_FILTER:
                if(aic_ble_only){
                    p_data[6] = 0x00;//status:success
                }
                break;
            case HCI_RMT_NAME_REQUEST:
                if(aic_ble_only){
                    p_data[6] = 0x00;//status:success
                }
                break;
            case HCI_LE_SET_EXTENDED_SCAN_ENABLE:
                if(aic_ble_only){
                    p_data[6] = 0x00;//status:success
                }
                break;

            case HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS:
                AICBTDBG(LOGINFO, "%s HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS set to 0x10 for vts\r\n", __func__);
                p_data[7] = 0x10;
                break;
            case HCI_BLE_READ_RESOLVING_LIST_SIZE:
                AICBTDBG(LOGINFO, "%s HCI_BLE_READ_RESOLVING_LIST_SIZE set to 0xb for vts\r\n", __func__);
                p_data[7] = 0x0b;
                break;
			default:
				break;
		}
	}
	else if(p_data[0] == DATA_TYPE_EVENT && p_data[1] == HCI_COMMAND_STATUS_EVT){
		opcode = *((uint16_t*)&p_data[5]);

		AICBTDBG(LOGINFO, "%s, aic_ble_only cmd status opcode:%04x \r\n", __func__, opcode);
		
		switch(opcode){
			case HCI_INQUIRY:
				if(aic_ble_only){
					p_data[3] = 0x00;//status:success
				}
				break;
			default:
				break;
		}
	}else if((p_data[0] == DATA_TYPE_EVENT && p_data[1] == HCI_VENDOR_SPEC_EVT)){
        AICBTDBG(LOGFW, "%s\r\n", (p_data + 17));
        write_fw_to_file((char*)(p_data + 17), (p_data[2]-17));
    }
	
}


static int userial_handle_recv_data(unsigned char *recv_buffer, unsigned int total_length,unsigned int *return_length)
{
    serial_data_type_t type = 0;
    unsigned char *p_data = recv_buffer;
    unsigned int length = total_length;
    uint8_t event;
    bool handle_ret = false;
    if (!length){
        ALOGE("%s, length is 0, return immediately", __func__);
        return total_length;
    }

	//AIC handle start
	aic_event_handle(recv_buffer);
	//AIC handle end

    switch (received_packet_state) {
        case AICBT_PACKET_IDLE:
            received_packet_bytes_need = 1;
            while(length) {
                type = p_data[0];
                length--;
                p_data++;
                if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
                    ALOGE("%s invalid data type: %d", __func__, type);
                    userial_send_hw_error();
                    vnd_userial.is_hardware_err = true;
                    assert((type > DATA_TYPE_COMMAND) && (type <= DATA_TYPE_EVENT));
                    if (!length)
                        return total_length;

                    continue;
                }
                break;
            }
            recv_packet_current_type = type;
            received_packet_state = AICBT_PACKET_TYPE;
            //fall through

        case AICBT_PACKET_TYPE:
            received_packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(recv_packet_current_type)];
            received_resvered_length = 0;
            received_packet_state = AICBT_PACKET_HEADER;
            //fall through

        case AICBT_PACKET_HEADER:
            if (length >= received_packet_bytes_need) {
                memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
                received_resvered_length += received_packet_bytes_need;
                length -= received_packet_bytes_need;
                p_data += received_packet_bytes_need;
            } else {
                memcpy(&received_resvered_header[received_resvered_length], p_data, length);
                received_resvered_length += length;
                received_packet_bytes_need -= length;
                length = 0;
                return total_length;
            }
            received_packet_state = AICBT_PACKET_CONTENT;

            if (recv_packet_current_type == DATA_TYPE_ACL) {
                received_packet_bytes_need = *(uint16_t *)&received_resvered_header[2];
            } else if (recv_packet_current_type == DATA_TYPE_EVENT){
                received_packet_bytes_need = received_resvered_header[1];
            } else {
                received_packet_bytes_need = received_resvered_header[2];
            }
            //fall through

        case AICBT_PACKET_CONTENT:
            if (recv_packet_current_type == DATA_TYPE_EVENT) {
                event = received_resvered_header[0];

                if (event == HCI_COMMAND_COMPLETE_EVT) {
                    if (received_resvered_length == 2) {
                        if (length >= 1) {
                            *p_data = 1;
                        }
                    }
                } else if (event == HCI_COMMAND_STATUS_EVT) {
                    if (received_resvered_length < 4) {
                        unsigned int act_len = 4 - received_resvered_length;
                        if (length >= act_len) {
                            *(p_data + act_len -1) = 1;
                        }
                    }
                }
            }
            if (length >= received_packet_bytes_need) {
                memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
                length -= received_packet_bytes_need;
                p_data += received_packet_bytes_need;
                received_resvered_length += received_packet_bytes_need;
                received_packet_bytes_need = 0;
            } else {
                memcpy(&received_resvered_header[received_resvered_length], p_data, length);
                received_resvered_length += length;
                received_packet_bytes_need -= length;
                length = 0;
                return total_length;
            }
            received_packet_state = AICBT_PACKET_END;
            //fall through

        case AICBT_PACKET_END:
            switch (recv_packet_current_type) {
                case DATA_TYPE_EVENT :
                handle_ret = userial_handle_event(received_resvered_header, received_resvered_length);
                if(handle_ret){
                    *return_length = 0;
                }
                break;
#ifdef CONFIG_SCO_OVER_HCI
                case DATA_TYPE_SCO :
                    userial_enqueue_recv_sco_data(received_resvered_header, received_resvered_length);
                break;
#endif
                default :

                break;
            }
            break;

        default:
            break;
    }

    received_packet_state = AICBT_PACKET_IDLE;
    received_packet_bytes_need = 0;
    recv_packet_current_type = 0;
    received_resvered_length = 0;

    return (total_length - length);
}
#endif

static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length)
{ 
    unsigned char buffer[1028] = {0};
    unsigned int length = 0;
    length = h5_int_interface->h5_int_read_data(&buffer[1], total_length);
    if (length == -1) {
        ALOGE("%s, error read length", __func__);
        assert(length != -1);
    }
    buffer[0] = type;
    length++;
    uint16_t transmitted_length = 0;
    unsigned int real_length = length;
#ifdef AIC_HANDLE_EVENT
    unsigned int read_length = 0;
    do {
        read_length += userial_handle_recv_data(buffer + read_length, real_length - read_length,&length);
    } while (vnd_userial.thread_running && read_length < total_length);
#endif

    while (length > 0) {
        ssize_t ret;
        AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
        switch (ret) {
            case -1:
                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                goto done;
            case 0:
                // If we wrote nothing, don't loop more because we
                // can't go to infinity or beyond
                goto done;
            default:
                transmitted_length += ret;
                length -= ret;
                break;
        }
    }
done:

    return;
}

//This recv data from driver which is sent or recv by the controller. The data type have ACL/SCO/EVENT
// direction CONTROLLER -----> BT HOST
static void userial_recv_uart_rawdata(unsigned char *buffer, unsigned int total_length)
{
    unsigned int length = total_length;
    uint16_t transmitted_length = 0;
#ifdef CONFIG_SCO_OVER_HCI
    AIC_BUFFER* skb_msbc_dec_data = NULL;
    bool is_sco = false;
#endif
#ifdef AIC_HANDLE_EVENT
    unsigned int read_length = 0;
    do {
        read_length += userial_handle_recv_data(buffer + read_length, total_length - read_length,&length);
    } while(read_length < total_length);
    
    if(buffer[0] == DATA_TYPE_EVENT && buffer[1] == HCI_VENDOR_SPEC_EVT){
        return;
    }
#endif

        //ALOGE("length %d,type %d", length,buffer[0]);
#ifdef CONFIG_SCO_OVER_HCI
        if (buffer[0] == DATA_TYPE_SCO) {
            is_sco = true;
            if(sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_MSBC){
                pthread_mutex_lock(&sco_cb.msbc_recv_mutex);
                if (!RtbQueueIsEmpty(sco_cb.recv_msbc_dec_data)) {
                    skb_msbc_dec_data = RtbDequeueHead(sco_cb.recv_msbc_dec_data);
                }
                pthread_mutex_unlock(&sco_cb.msbc_recv_mutex);
                if(!skb_msbc_dec_data) {
#if AIC_SCO_UART_SUPPORT
                    if (btif_aic_sco_state == BTIF_AIC_SCO_STATE_ON){
                        AIC_BUFFER* send_p_buf = NULL; 
                        send_p_buf = RtbDequeueHead(btif_aic_sco_cb.snd_recv_msg_queue);
                        if (send_p_buf){
                            //ALOGE("send len %d, get len %ld", send_p_buf->Length, RtbGetQueueLen(btif_aic_sco_cb.snd_recv_msg_queue));
                            userial_send_sco_to_controller(send_p_buf->Data, send_p_buf->Length);
                            RtbFree(send_p_buf);
                        }
                    }
#endif
                    return;
                }
                buffer = skb_msbc_dec_data->Data;
                length = 244;
                total_length = 244;
            }
#if AIC_SCO_UART_SUPPORT
          //ALOGE("%s,%d\n", __func__, (int)btif_aic_sco_state);
          if (btif_aic_sco_state == BTIF_AIC_SCO_STATE_ON) {
            AIC_BUFFER* p_buf = RtbAllocate(length, 0);
            AIC_BUFFER* send_p_buf = NULL; 
            memcpy(p_buf->Data, buffer, length);
            RtbAddTail(p_buf, length);
            pthread_mutex_lock(&btif_aic_sco_cb.worker_recv_mutex);
            RtbQueueTail(btif_aic_sco_cb.data_msg_queue,p_buf);
            pthread_cond_signal(&btif_aic_sco_cb.worker_thread_cond);
            pthread_mutex_unlock(&btif_aic_sco_cb.worker_recv_mutex);

            send_p_buf = RtbDequeueHead(btif_aic_sco_cb.snd_recv_msg_queue);
            if (send_p_buf){
                //ALOGE("send len %d, get len %ld", send_p_buf->Length, RtbGetQueueLen(btif_aic_sco_cb.snd_recv_msg_queue));
                userial_send_sco_to_controller(send_p_buf->Data, send_p_buf->Length);
                RtbFree(send_p_buf);
            }
          }
#endif
        }
        while (!is_sco && length > 0 && vnd_userial.thread_running) {
            ssize_t ret;
            AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
            switch (ret) {
            case -1:
                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                goto done;
            case 0:
                // If we wrote nothing, don't loop more because we
                // can't go to infinity or beyond
                goto done;
            default:
                transmitted_length += ret;
                length -= ret;
                break;
            }
        }
done:
        if(skb_msbc_dec_data){
            RtbFree(skb_msbc_dec_data);
            skb_msbc_dec_data = NULL;
        }
#else
        while (length > 0 && vnd_userial.thread_running) {
            ssize_t ret;
            AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
            switch (ret) {
            case -1:
                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                goto done;
            case 0:
                // If we wrote nothing, don't loop more because we
                // can't go to infinity or beyond
                goto done;
            default:
                transmitted_length += ret;
                length -= ret;
                break;
            }
        }
done:
#endif

    return;
}

void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length)
{
      uint16_t transmitted_length = 0;
      unsigned int real_length = total_length;

      while (vnd_userial.thread_running && (total_length > 0)) {
          ssize_t ret;
          AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, total_length));
          switch (ret) {
              case -1:
                  ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
                  goto done;
              case 0:
                  // If we wrote nothing, don't loop more because we
                  // can't go to infinity or beyond
                  goto done;
              default:
                  transmitted_length += ret;
                  total_length -= ret;
                  break;
          }
      }
  done:
      return;

}

static void *userial_recv_socket_thread(void *arg)
{
    AIC_UNUSED(arg);
    struct epoll_event events[64];
    int j;
    while (vnd_userial.thread_running) {
        int ret;
        do {
            ret = epoll_wait(vnd_userial.epoll_fd, events, 32, 500);
        } while(vnd_userial.thread_running && ret == -1 && errno == EINTR);

        if (ret == -1) {
            ALOGE("%s error in epoll_wait: %s", __func__, strerror(errno));
        }
        for (j = 0; j < ret; ++j) {
            struct aic_object_t *object = (struct aic_object_t *)events[j].data.ptr;
            if (events[j].data.ptr == NULL)
                continue;
            else {
                if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && object->read_ready)
                    object->read_ready(object->context);
                if (events[j].events & EPOLLOUT && object->write_ready)
                    object->write_ready(object->context);
            }
        }
    }
    //vnd_userial.thread_socket_id = -1;
    ALOGD("%s exit", __func__);
    return NULL;
}

static int userial_hci_data_read_process(unsigned char *read_buffer,int len,int bt_dev_fd)
{
    int ret_len = -1, ret = 0;
    if(bt_dev_fd <= 0){
        ret = -1;
        ALOGE("%s ,fd = %d\n",__func__,bt_dev_fd);
        return ret;
    }
    if(aicbt_transtype & AICBT_TRANS_UART){
        bool read_done = false;
        int len_type;
        int len_header;
        int len_data;
        int offset = 0;
        uint8_t tmp_buf[2048];
        HCI_RXST_T state = HCI_MSGTYPE_ST;
        uint8_t evt_len = 0;
        uint16_t acl_len = 0;
        uint8_t sco_len = 0;
        uint16_t check_offset = 0;

        while(!read_done){
            switch(state){
                case HCI_MSGTYPE_ST:
                    {
						AICBTDBG(LOGDEBUG, "%s,HCI_MSGTYPE_ST\r\n",__func__);
                        len_type = read(bt_dev_fd, tmp_buf, HCI_TYPE_LEN);
                        if (len_type != HCI_TYPE_LEN) {
                            AICBTDBG(LOGERROR, "%s,read  len_type error \n",__func__);
                            ret = -ESTRPIPE;
                            goto fail;
                        }
                        read_buffer[0] = tmp_buf[0];
                        state = HCI_LEN_ST;
                        offset = 0;
                    }
                    break;
                case HCI_LEN_ST:
                    {
						AICBTDBG(LOGDEBUG, "%s,HCI_LEN_ST \r\n",__func__);
                        if(read_buffer[0] == HCI_EVT_PKT){
                            len_header = read(bt_dev_fd, (tmp_buf+offset), (HCI_EVT_HEADER_LEN-offset));
                            if (!len_header) {
                                AICBTDBG(LOGERROR, "%s,read  evt len_header error\r\n",__func__);
                                ret = -ESTRPIPE;
                                goto fail;
                            }
                            if ((len_header+offset) < HCI_EVT_HEADER_LEN) {
                                ALOGE("%s,read  evt len_header continue,%d \n",__func__,len_header);
                                offset += len_header;
                                break;
                            }
                            evt_len = tmp_buf[1];
							AICBTDBG(LOGDEBUG, "%s,evt_len = %d \n",__func__,evt_len);
                        }else if(read_buffer[0] == HCI_ACL_PKT){
                            len_header = read(bt_dev_fd, (tmp_buf+offset), (HCI_ACL_HEADER_LEN-offset));
                            if (!len_header) {
                                AICBTDBG(LOGERROR, "%s,read  acl len_header error\r\n",__func__);
                                ret = -ESTRPIPE;
                                goto fail;
                            }
                            if ((len_header+offset) < HCI_ACL_HEADER_LEN) {
                                    AICBTDBG(LOGDEBUG, "%s,read  acl len_header continue %d \n",__func__,len_header);
                                offset += len_header;
                                break;
                            }
                            acl_len = (uint16_t)tmp_buf[2] |((uint16_t)tmp_buf[3]<<8);
                            AICBTDBG(LOGDEBUG, "%s,acl_len = %d \n",__func__,acl_len);
                        }else if(read_buffer[0] == HCI_SCO_PKT){
                            len_header = read(bt_dev_fd, (tmp_buf+offset), (HCI_SCO_HEADER_LEN-offset));
                            if (!len_header) {
                                AICBTDBG(LOGERROR, "%s,read  sco len_header error\r\n",__func__);
                                ret = -ESTRPIPE;
                                goto fail;
                            }
                            if ((len_header+offset) < HCI_SCO_HEADER_LEN) {
                                AICBTDBG(LOGDEBUG, "%s,read  sco len_header continue %d \n",__func__,len_header);
                                offset += len_header;
                                break;
                            }
                            sco_len = tmp_buf[2];
                            AICBTDBG(LOGDEBUG, "%s,sco_len = %d \n",__func__,sco_len);
                        }else{
                            AICBTDBG(LOGERROR, "%s,hci len st error \n",__func__);
                            ret = -ESTRPIPE;
                            goto fail;
                        }
                        len_header+=offset;
                        memcpy(read_buffer+len_type,tmp_buf,len_header);
                        state = HCI_DATA_ST;
                        offset = 0;
                    }
                    break;
                case HCI_DATA_ST:
                    {
						AICBTDBG(LOGDEBUG, "%s,HCI_DATA_ST \r\n",__func__);
                        if(read_buffer[0] == HCI_EVT_PKT){
                            len_data = read(bt_dev_fd, tmp_buf, (evt_len-check_offset));
                            if (!len_data) {
                                AICBTDBG(LOGERROR, "%s,read  evt len_data error ,len_data =%d\n",__func__,len_data);
                                ret = -ESTRPIPE;
                                goto fail;
                            }
							if (len_data+check_offset < evt_len) {
                                AICBTDBG(LOGDEBUG, "%s,len_data =%d,continue\n",__func__,len_data);
								memcpy(read_buffer+len_type+len_header+check_offset,tmp_buf,len_data);
								check_offset += len_data;
                                break;
							}
                            memcpy(read_buffer+len_type+len_header+check_offset,tmp_buf,len_data);
							len_data = evt_len;
                        }else if(read_buffer[0] == HCI_ACL_PKT){
                            len_data = read(bt_dev_fd, tmp_buf, (acl_len-check_offset));
                            if (!len_data) {
                                AICBTDBG(LOGERROR, "%s,read  acl len_data error ,len_data =%d\n",__func__,len_data);
                                ret = -ESTRPIPE;
                                goto fail;
                            }
							if (len_data+check_offset < acl_len) {
                                AICBTDBG(LOGDEBUG, "%s,len_data =%d,continue\n",__func__,len_data);
								memcpy(read_buffer+len_type+len_header+check_offset,tmp_buf,len_data);
								check_offset += len_data;
                                break;
							}
                            memcpy(read_buffer+len_type+len_header+check_offset,tmp_buf,len_data);
							len_data = acl_len;
                        }else if(read_buffer[0] == HCI_SCO_PKT){
                            len_data = read(bt_dev_fd, tmp_buf, (sco_len-check_offset));
                            if (!len_data) {
                                AICBTDBG(LOGERROR, "%s,read  sco len_data error ,len_data =%d\n",__func__,len_data);
                                ret = -ESTRPIPE;
                                goto fail;
                            }
							if (len_data+check_offset < sco_len) {
                                AICBTDBG(LOGDEBUG, "%s,len_data =%d,continue\n",__func__,len_data);
								memcpy(read_buffer+len_type+len_header+check_offset,tmp_buf,len_data);
								check_offset += len_data;
                                break;
							}
                            memcpy(read_buffer+len_type+len_header+check_offset,tmp_buf,len_data);
							len_data = sco_len;
                        }else{
                            AICBTDBG(LOGERROR, "%s,hci data st error \n",__func__);
                            ret = -ESTRPIPE;
                            goto fail;
                        }

                        state = HCI_DONE_ST;
                        check_offset = 0;
                    }
                    break;
                case HCI_DONE_ST:
					AICBTDBG(LOGDEBUG, "%s,HCI_DONE_ST \r\n",__func__);
                    read_done = true;
                    ret_len = len_type+len_header+len_data;
                    break;
                default:
                    break;
            }
        }
    }
    return ret_len;
fail:
    return ret;
}

static void *userial_recv_uart_thread(void *arg)
{
    AIC_UNUSED(arg);
    struct pollfd pfd[2];
    pfd[0].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
    pfd[0].fd = vnd_userial.signal_fd[1];
    pfd[1].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
    pfd[1].fd = vnd_userial.fd;
    int ret;
    unsigned char read_buffer[2056] = {0};
    ssize_t bytes_read;
    while (vnd_userial.thread_running) {
        do {
            ret = poll(pfd, 2, 500);
        } while (ret == -1 && errno == EINTR && vnd_userial.thread_running);

        //exit signal is always at first index
        if (pfd[0].revents && !vnd_userial.thread_running) {
            ALOGD("receive exit signal and stop thread");
            return NULL;
        }

        if (pfd[1].revents & POLLIN) {
            if(aicbt_transtype & AICBT_TRANS_UART){
                bytes_read = userial_hci_data_read_process(read_buffer,sizeof(read_buffer),vnd_userial.fd);
                if (bytes_read < 0) {
                    ALOGE("%s, read fail, error : %s", __func__, strerror(errno));
                    userial_send_hw_error();
                    vnd_userial.is_hardware_err = true;
                    continue;
                }
            }else if(aicbt_transtype & AICBT_TRANS_USB){
                AIC_NO_INTR(bytes_read = read(vnd_userial.fd, read_buffer, sizeof(read_buffer)));
                if (!bytes_read)
                    continue;
                if (bytes_read < 0) {
                    ALOGE("%s, read fail, error : %s", __func__, strerror(errno));
                    userial_send_hw_error();
                    vnd_userial.is_hardware_err = true;
                    continue;
                }
            }else{
                assert((aicbt_transtype & AICBT_TRANS_USB) || (aicbt_transtype & AICBT_TRANS_UART));
            }

            if (aicbt_transtype & AICBT_TRANS_H5) {
                h5_int_interface->h5_recv_msg(read_buffer, bytes_read);
            } else {
                userial_recv_uart_rawdata(read_buffer, bytes_read);
                if(read_buffer[0] == 0x04 && read_buffer[1] == HCI_VENDOR_SPEC_EVT){
                    continue;
                }
                aic_btsnoop_capture(read_buffer, true);
            }
        }

        if (pfd[1].revents & (POLLERR|POLLHUP)) {
            ALOGE("%s poll error, fd : %d", __func__, vnd_userial.fd);
            vnd_userial.btdriver_state = false;
            close(vnd_userial.fd);
            userial_send_hw_error();
            vnd_userial.is_hardware_err = true;
            return NULL;
        }
        if (ret < 0) {
            ALOGE("%s : error (%d)", __func__, ret);
            continue;
        }
    }
    vnd_userial.thread_uart_id = -1;
    ALOGD("%s exit", __func__);
    return NULL;
}

int userial_socket_open()
{
    int ret = 0;
    struct epoll_event event;
    memset(chgloclname,0,252);
    memset(eir,0,245);
    memset(cod,0,7);
    memset(simple_pair_mode,0,5);
    memset(le_host_support,0,6);
    memset(secure_conn_host_support,0,5);
    memset(le_set_event_mask,0,12);
    memset(set_event_mask,0,12);
    memset(set_le_random_addr,0,10);
    if ((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, vnd_userial.uart_fd)) < 0) {
        ALOGE("%s, errno : %s", __func__, strerror(errno));
        return ret;
    }

    if ((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, vnd_userial.signal_fd)) < 0) {
        ALOGE("%s, errno : %s", __func__, strerror(errno));
        return ret;
    }

    vnd_userial.epoll_fd = epoll_create(64);
    if (vnd_userial.epoll_fd == -1) {
        ALOGE("%s unable to create epoll instance: %s", __func__, strerror(errno));
        return -1;
    }

    aic_socket_object.fd = vnd_userial.uart_fd[1];
    aic_socket_object.read_ready = userial_recv_H4_rawdata;
    memset(&event, 0, sizeof(event));
    event.events |= EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
    event.data.ptr = (void *)&aic_socket_object;
    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.uart_fd[1], &event) == -1) {
        ALOGE("%s unable to register fd %d to epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));
        close(vnd_userial.epoll_fd);
        vnd_userial.epoll_fd = -1;
        return -1;
    }

    event.data.ptr = NULL;
    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
        ALOGE("%s unable to register signal fd %d to epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
        close(vnd_userial.epoll_fd);
        vnd_userial.epoll_fd = -1;
        return -1;
    }
    pthread_attr_t thread_attr;
    pthread_attr_init(&thread_attr);
    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
    vnd_userial.thread_running = true;
    if (pthread_create(&vnd_userial.thread_socket_id, &thread_attr, userial_recv_socket_thread, NULL) != 0) {
        ALOGE("pthread_create : %s", strerror(errno));
        close(vnd_userial.epoll_fd);
        vnd_userial.epoll_fd = -1;
        vnd_userial.thread_socket_id = -1;
        return -1;
    }


    if (pthread_create(&vnd_userial.thread_uart_id, &thread_attr, userial_recv_uart_thread, NULL) != 0) {
        ALOGE("pthread_create : %s", strerror(errno));
        close(vnd_userial.epoll_fd);
        vnd_userial.thread_running = false;
        pthread_join(vnd_userial.thread_socket_id, NULL);
        vnd_userial.thread_socket_id = -1;
        return -1;
    }
#if 0
    vnd_userial.cpoll_fd = epoll_create(64);
    assert (vnd_userial.cpoll_fd != -1);

    vnd_userial.event_fd = eventfd(10, EFD_NONBLOCK);
    assert(vnd_userial.event_fd != -1);
    if (vnd_userial.event_fd != -1) {
        memset(&event, 0, sizeof(event));
        event.events |= EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
        if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_ADD, vnd_userial.event_fd, &event) == -1) {
            ALOGE("%s unable to register fd %d to cpoll set: %s", __func__, vnd_userial.event_fd, strerror(errno));
            assert(false);
        }

        event.data.ptr = NULL;
        if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
            ALOGE("%s unable to register fd %d to cpoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
            assert(false);
        }
    }
#endif
//    AIC_btservice_init();
    ret = vnd_userial.uart_fd[0];
    return ret;
}

int userial_vendor_usb_ioctl(int operation, void *param)
{
    int retval;
     AICBTDBG(LOGINFO, "aic userial_vendor_usb_ioctl %d", operation);
    retval = ioctl(vnd_userial.fd, operation, param);
    if (retval == -1)
         AICBTDBG(LOGERROR, "%s: error: %d : %s", __func__,errno, strerror(errno));
    return retval;
}

int userial_vendor_usb_open(void)
{
    if ((vnd_userial.fd = open(vnd_userial.port_name, O_RDWR)) == -1) {
        ALOGE("%s: unable to open %s: %s", __func__, vnd_userial.port_name, strerror(errno));
        return -1;
    }

    vnd_userial.btdriver_state = true;
    AICBTDBG(LOGINFO, "device fd = %d open", vnd_userial.fd);

    return vnd_userial.fd;
}

